当Java程序性能达不到既定目标,且其他优化手段都已经穷尽时,通常需要调整垃圾回收器来进一步提高性能,称为GC优化。但GC算法复杂,影响GC性能的参数众多,且参数调整又依赖于应用各自的特点,这些因素很大程度上增加了GC优化的难度。即便如此,GC调优也不是无章可循,仍然有一些通用的思考方法。
总结了GC优化的两个目的:
1. 将进入老年代的对象数量降到最低
2. 减少Full GC的执行时间
将进入老年代的对象数量降到最低
除了可以在JDK 7及更高版本中使用的G1收集器以外,其他分代GC都是由Oracle JVM提供的。关于分代GC,就是对象在Eden区被创建,随后被转移到Survivor区,在此之后剩余的对象会被转入老年代。也有一些对象由于占用内存过大,在Eden区被创建后会直接被传入老年代。老年代GC相对来说会比新生代GC更耗时,因此,减少进入老年代的对象数量可以显著降低Full GC的频率。你可能会以为减少进入老年代的对象数量意味着把它们留在新生代,事实正好相反,新生代内存的大小是可以调节的。
降低Full GC的时间
Full GC的执行时间比Minor GC要长很多,因此,如果在Full GC上花费过多的时间(超过1s),将可能出现超时错误。
如果通过减小老年代内存来减少Full GC时间,可能会引起OutOfMemoryError或者导致Full GC的频率升高。
另外,如果通过增加老年代内存来降低Full GC的频率,Full GC的时间可能因此增加。
因此,你需要把老年代的大小设置成一个“合适”的值。
影响GC性能的参数
表1:GC优化需要考虑的JVM参数
参数 | 描述 | |
---|---|---|
-Xms | 初始堆大小 | |
-Xmx | 最大堆大小 | |
-XX:NewRatio | 新生代和老年代的内存比 | |
-XX:NewSize | 新生代内存大小 | |
-XX:SurvivorRatio | Eden区和Survivor区的内存比 |
笔者在进行GC优化时最常用的参数是-Xms,-Xmx和-XX:NewRatio。-Xms和-Xmx参数通常是必须的,所以NewRatio的值将对GC性能产生重要的影响。
有些人可能会问如何设置永久代内存大小,你可以用-XX:PermSize和-XX:MaxPermSize参数来进行设置,但是要记住,只有当出现OutOfMemoryError错误时你才需要去设置永久代内存。