JVM:对象什么时候会被存储到老年代?

100 阅读3分钟
对象存储到老年代的几种情况
  1. 对象除了达到 15 的年龄会被转移到老年代。
  2. JVM 还有一种动态对象年龄判断机制,如果 Survivor 区域里一批对象所占内存到了 Survivor 的 50%,那么此时大于等于这批最大年龄的对象会直接进入老年代。
    • 实际这个规则运行的时候的逻辑:年龄1 + 年龄2 + 年龄n 的多个年龄对象总和超过了Survivor区域的50%,此时就会把年龄 >= n的对象都放入老年代。
  3. 大对象直接进入老年代,不会进入 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 存在的一种机制:老年代分配空间担保机制

老年代分配空间担保机制

  1. 每次发生 young gc 前,JVM 都会判断老年代当前所剩内存是否大于新生代所有对象总和。如果大于,直接执行 young gc。
  2. 如果老年代所剩内存小于新生代总和,看是否有配置 -XX:HandlePromotionFailure(jdk1.6有效,jdk1.7 以后默认开启),没有则直接执行 full gc。
  3. 如果有该配置,或者是 jdk1.7 以后,就先判断之前新生代每次存活的平均内存大小,是否小于当前老年代所剩空间。如果小于,说明老年代大概率能放下,直接执行 minor gc。否则,直接执行 full gc。

在了解上面的机制之后,就能明白触发 Old GC 的时机

  1. 发生 Young GC 时进行空间担保机制判断,老年代空间不够则进行一次 Old GC。
  2. 执行 Young GC 后有一批对象要进入老年代,如果老年空间不够,补充进行一次 Old GC。(因为空间担保机制的平均内存也是有概率放不下老年代的)。
  3. 老年代内存使用率超过一定比例,CMS 垃圾回收器是 92%,触发一次 Old GC。(如果使用的是常见的 CMS 垃圾回收器,可通过 XX:CMSInitiatingOccupancyFraction 进行配置,默认为 92 %)。