本文是对阅读《Java性能权威指南》的一些总结。
如果不能忍受Full GC,默认设置也达不到你的期望值,并且应用停顿时间和你的目标不一致,那么你需要对GC调优。
调优的基本想法如下:
1,能在新生eden区代回收的资源,尽量不让资源进入到survivor区。
2,能在survivor区回收的资源,尽量不让资源进入old区。
其实,我们的最终目的是尽量不让太多资源进入old区,如果old区满了的话,就会引发Full GC,这是我们不想要的。
而当survivor区满了的话,就会把不能释放的资源放入到old区。
eden区存放对象时,也需要注意一些问题。如果存放的对象太大的话,可能会产生两个问题:
1,无法放到堆的TLAB区。
(eden,survivor和old都属于堆,只是占用的比例不同。而TLAB是eden区的一部分)
2,可能会直接放到survivor区或old区。
为什么上面的两点会是问题呢。
当一个对象生成后,如果对象很快就用完,并想释放掉的话,最好放到eden区,
因为每次GC时,都会把eden区的无用的资源清除掉,有用的放到survivor或old区。
这样,一些很快用完的资源会被快速释放掉。
但如果放到old区的话,每次GC时,不会清理old区,只有在old区满了之后,才会清理,并压缩
old区(压缩的目的是减少磁盘碎片),也就是Full GC。
所以,资源尽可能的放到eden区,除非这次资源会用很长时间。
为什么无法放到堆的TLAB区也是问题呢?
因为TLAB区虽然也是堆上的一部分,但这部分的存取速度非常快。
原理是这部分区域是线程私有的,不是线程共享的。
因为是私有的,所以访问时,存在和其它线程抢占问题,也就不用加锁来保证安全。
所以,如果资源能放在TLAB里,就尽量使资源放到TLAB里。
具体放到哪,是由对象的大小和TLAB的大小或各种区域的块大小决定的。
具体如何优化能让资源放在我们设想的区域里,以后再说。
磁盘碎片