对象存储到老年代的几种情况
- 对象除了达到 15 的年龄会被转移到老年代。
- JVM 还有一种动态对象年龄判断机制,如果 Survivor 区域里一批对象所占内存到了 Survivor 的 50%,那么此时大于等于这批最大年龄的对象会直接进入老年代。
- 实际这个规则运行的时候的逻辑:年龄1 + 年龄2 + 年龄n 的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄 >= n的对象都放入老年代。
- 大对象直接进入老年代,不会进入 eden 区,可以根据
-XX:PretenureSizeThreshold
来设置大小,如1048576,表示 1 MB。
对象占用的内存一多,就会发生 GC,但是很多博客对 GC 的概念并不严谨,比如混淆 Full GC 和 Old GC。
GC 概念准确定义
- Young GC、Minor GC:新生代中的 Eden 内存区域被占满后发生的垃圾回收。
- Old GC:老年代内存区域被占满后的垃圾回收。
- Full GC:针对的是新生代、老年代、办法区的全体内存空间的垃圾回收。也就是整个 JVM 所有内存区域一次整体的垃圾回收。
- Mixed GC:G1 垃圾回收器特有的概念,会同时回收新生代和老年代。
梳理完 GC 的概念后,到底什么时候会触发 Old GC 呢
触发 Old GC 的几种情况
总是说老年代空间满了就会发生 Old GC,那具体到底是什么时机呢?
在介绍触发 Old GC 的时机之前,需要先清楚 JVM 存在的一种机制:老年代分配空间担保机制。
老年代分配空间担保机制
- 每次发生 young gc 前,JVM 都会判断老年代当前所剩内存是否大于新生代所有对象总和。如果大于,直接执行 young gc。
- 如果老年代所剩内存小于新生代总和,看是否有配置
-XX:HandlePromotionFailure
(jdk1.6有效,jdk1.7 以后默认开启),没有则直接执行 full gc。 - 如果有该配置,或者是 jdk1.7 以后,就先判断之前新生代每次存活的平均内存大小,是否小于当前老年代所剩空间。如果小于,说明老年代大概率能放下,直接执行 minor gc。否则,直接执行 full gc。
在了解上面的机制之后,就能明白触发 Old GC 的时机:
- 发生 Young GC 时进行空间担保机制判断,老年代空间不够则进行一次 Old GC。
- 执行 Young GC 后有一批对象要进入老年代,如果老年空间不够,补充进行一次 Old GC。(因为空间担保机制的平均内存也是有概率放不下老年代的)。
- 老年代内存使用率超过一定比例,CMS 垃圾回收器是 92%,触发一次 Old GC。(如果使用的是常见的 CMS 垃圾回收器,可通过
XX:CMSInitiatingOccupancyFraction
进行配置,默认为 92 %)。