迁移64位虚拟机未必性能更好
业务量上升以后,需要使用的内存随之增加,而在通常32位系统上,单个进程占用的最大内存通常是2GB,且考虑到堆外内存的使用,32位机器可能无法满足内存要求,一种常见的应对方式就是换用64位服务器。而对于Java,由于指针膨胀和字节对齐,同一个程序在64位虚拟机上占用的内存会多于32位虚拟机。开发者换用64位虚拟机后,很可能会增加虚拟机的堆大小,而这将导致 Full GC 垃圾回收的时间大大增加,导出堆快照也变得困难。
因此,使用64位虚拟机增加内存时,需要特别注意对内存的使用,尽量不要触发Full
GC导致长时间停顿。另一种方法是建立32位虚拟机的集群来提高性能。
堆外内存溢出
Java本地方法调用,如调用C++实现的本地模块、NIO的DirectByteBuffer,都会占用大量内存。而在开发中,开发者往往重点关注了堆内存的大小,在内存溢出时也倾向于增加堆内存,而忽视了堆外内存的使用。堆外内存并不会像堆内存一样不足马上通知GC进行垃圾回收,堆外内存只能等待老年代空间不足进行Full
GC时顺便回收内存,否则堆外内存只能等到空间不足时抛出内存溢出异常,然后请求GC进行回收。
因此,配置虚拟机,除考虑常规的堆大小外,优化时还需要考虑Direct
Memory、线程栈、socket缓冲区、JNI代码、虚拟机、GC占用的内存大小。
外部命令的时间消耗
Java开发中如果需要执行shell脚本,可以使用Runtime.getRuntime().exec方法,还能从返回的Process对象中读取标准输出、错误输出、等待执行结束。根据方法注释,该方法首先复制当前进程产生一个子进程,在子进程中执行命令,结束后退出子进程。
进程的复制比较消耗CPU和内存,应尽量通过Java程序本身去完成相关功能。
多线程使用线程池
Java虚拟机中没有给用户用的多进程方法,并行处理更多地使用多线程方式。默认情况下,Linux限制用户的线程数量上限为1024,当然包括了系统中运行的所有线程。通常情况下,线程资源不会被耗尽,但多线程程序如果频繁创建新线程也会遇到线程资源不足的情况。一方面,可以调整系统设置,提高线程数上限,另一方面,应尽量避免频繁创建线程。线程虽小,创建时一样要消耗时间和内存。
多线程程序应尽量采用Java的线程池,这样线程的个数总体可控,使用时可以避免创建线程的时间消耗。Java提供了多种功能强大的线程池类型,基于线程池可以对任务进行缓存、按照一定的时间频率执行任务、返回执行结果、分叉与合并等。
网友评论