JVM如何调优?

一、什么是JVM调优?

所谓JVM调优就是指调整Java虚拟机的堆内存大小。那么内存的设置该怎么设置呢?设置成多大比较合适,既不浪费内存,又不影响性能呢?

分析:依据的原则是根据Java Performance里面的推荐公式来进行设置。

具体来讲:  

  Java整个堆大小设置,Xmx 和 Xms设置为老年代存活对象的3-4倍,即FullGC之后的老年代内存占用的3-4倍  

  永久代 PermSize和MaxPermSize设置为老年代存活对象的1.2-1.5倍。  

  年轻代Xmn的设置为老年代存活对象的1-1.5倍。  

  老年代的内存大小设置为老年代存活对象的2-3倍。

说明:

  1、Sun官方建议年轻代的大小为整个堆的3/8左右, 所以按照上述设置的方式,基本符合Sun的建议。        

  2、堆大小=年轻代大小+年老代大小, 即xmx=xmn+老年代大小 。 Permsize不影响堆大小。      

  3、为什么要按照上面的来进行设置呢? 没有具体的说明,但应该是根据多种调优之后得出的一个结论。

 二、如何确认老年代存活对象大小?

  方式1(推荐/比较稳妥):      

  JVM参数中添加GC日志,GC日志中会记录每次FullGC之后各代的内存大小,观察老年代GC之后的空间大小。可观察一段时间内(比如2天)的FullGC之后的内存情况,根据多次的FullGC之后的老年代的空间大小数据来预估FullGC之后老年代的存活对象大小(可根据多次FullGC之后的内存大小取平均值)  

  方式2:(强制触发FullGC, 会影响线上服务,慎用)      

  方式1的方式比较可行,但需要更改JVM参数,并分析日志。同时,在使用CMS回收器的时候,有可能不能触发FullGC(只发生CMS GC),所以日志中并没有记录FullGC的日志。在分析的时候就比较难处理。      

  所以,有时候需要强制触发一次FullGC,来观察FullGC之后的老年代存活对象大小。      

  注:强制触发FullGC,会造成线上服务停顿(STW),要谨慎,建议的操作方式为,在强制FullGC前先把服务节点摘除,FullGC之后再将服务挂回可用节点,对外提供服务      

  在不同时间段触发FullGC,根据多次FullGC之后的老年代内存情况来预估FullGC之后的老年代存活对象大小

三、如何触发FullGC ?

  使用jmap工具可触发FullGC                  

  jmap -dump:live,format=b,file=heap.bin <pid> 将当前的存活对象dump到文件,此时会触发FullGC                

  jmap -histo:live <pid> 打印每个class的实例数目,内存占用,类全名信息.live子参数加上后,只统计活的对象数量. 此时会触发FullGC

四、总结

  在内存相对紧张的情况下,可以按照上述的方式来进行内存的调优, 找到一个在GC频率和GC耗时上都可接受的一个内存设置,可以用较小的内存满足当前的服务需要  

  但当内存相对宽裕的时候,可以相对给服务多增加一点内存,可以减少GC的频率,GC的耗时相应会增加一些。

  一般要求低延时的可以考虑多设置一点内存, 对延时要求不高的,可以按照上述方式设置较小内存。  

  补充:  永久代(方法区)并不在堆内,所以之前有看过一篇文章中描述的 整个堆大小=年轻代+年老代+永久代的描述是不正确的。

猜你喜欢

转载自www.cnblogs.com/baichunyu/p/11990886.html