重新回过头来看一些 JVM,思考一个问题:分出一个永久代我可以理解,为什么又要把堆分成新生代和老年代呢?私以为划分成新生代和老年代是因为它们里面对象的性质不同,要用不同的垃圾回收算法来回收效率才高,是为垃圾回收器服务才分出新生代和老年代的。
本文说明新生代、老年代和永久代中对象的特性,以及何时它们何时触发 GC。
|
|
新生代
大部分对象存活的周期很短,就会放在新生代中。ParNew垃圾收集器会使用复制算法,回收新生代中的对象。复制算法中会将新生代分成 Eden 区和两个 Survivor 区,当 Eden 区满的时候就会触发垃圾回收算法。
老年代
少部分对象存活周期比较长,或者因为一些特殊原因会进入到老年代。那么什么样的情况下,对象会进入老年代呢?
一个实例对象在新生代中,成功躲过 15 次垃圾,就说明他已经15岁了。成为老人的它就能进入到老年代了。
具体几岁算是一个老人可以通过
-XX:MaxTenuringThreshold
参数进行设置。动态年龄判断,当前放对象的 Survivor 区域里,一批对象的总大小大于了这块 Survivor区域内存大小的50%,那么此时大于等于这批对象年龄的对象,就可以直接进入老年代。
大对象直接进入老年代,可以通过
-XX:PretenureSizeThreshold
参数进行设置Minor GC 之后发现剩余对象太多,无法放到另一个 Survivor 区,这些对象会直接进入老年代
老年代什么时候会触发 Old GC 呢?其实总结起来有 2 种情况:
- 老年代未开启分配担保,老年代对象大小小于新生代中对象大小;老年代开启分配担保,但是老年代对象大小小于历次 Minor GC 之后进入老年代对象的大小。以上情况会进行 Old GC。
- 经过 Minor GC 之前的检查,正式进行 Minor GC 后,Survivor 放不下剩余对象,老年代也放不下剩余对象,就会进行 Old GC。
如果 Old GC 之后老年代还是放不下剩余对象,就会 OOM。
具体关于老年代未开启分配机制,以及触发 Minor GC 和 Old GC 流程的内容,可以看《图解GC的过程》
永久代
JVM 里的永久代其实就是方法区,可以认为永久代就是放一些类信息的。
永久代一般不会发生 GC,具体情况还不是很清楚,以后会补充。