JVM调优经验

在JVM配置方面,我们一般可以先使用默认配置,这些基本的初始参数可以保证一般的应用程序的稳定运行。在测试中,我们可以根据系统的运行状况,比如会话并发情况、会话时间等,结合gc日志、内存监控和使用的垃圾收集器等进行合理的调整。当老年代内存过小时,可能会引起频繁的Full GC,而当内存过大时,Full GC的时间会特别长。

那么JVM的配置,比如新生代和老年代,应该配置多大才是最合适的呢?答案是不确定的,调优是一个寻找答案的过程。在物理内存一定的情况下,新生代设置越大,老年代就越小,Full GC的频率就越高,但Full GC的时间就会越短。相反,新生代设置越小,老年代就越大,Full GC的频率就越低,但每次Full GC的时间就会越长。根据我的建议,我们应该采取以下配置:

  • 将-Xms和-Xmx的值设置成相等,堆大小默认为-Xms指定的大小。当默认空闲堆内存小于40%时,JVM会扩大堆到-Xmx指定的大小;当空闲堆内存大于70%时,JVM会减小堆到-Xms指定的大小。如果在Full GC后无法满足内存需求,会进行动态调整,但这个阶段会消耗较多的资源。

  • 新生代尽量设置大一些,让对象在新生代多存活一段时间,每次Minor GC都要尽可能多地收集垃圾对象,以防止或延迟对象进入老年代,从而减少应用程序发生Full GC的频率。

  • 如果使用CMS收集器,新生代可以不用太大,因为CMS的并行收集速度很快,收集过程中比较耗时的并发标记和并发清除阶段都可以与用户线程并发执行。

  • 对于方法区大小的设置,对于1.6之前的版本,需要考虑系统运行时动态增加的常量、静态变量等;而对于1.7版本,只要能够装下启动时和后期动态加载的类信息就可以了。

在代码实现方面,出现性能问题(比如程序等待和内存泄漏)除了可能存在JVM配置的问题外,代码实现本身也有很大的关系: