jvm – 内存空间提到了,创建对象的时候,对象是在堆内存中创立的。但堆内存又分为新生代和老年代,新生代又细分 Eden 空间、From Survivor 空间、To Survivor 空间。咱们创立的类到底在哪里?
对象优先在 Eden 调配
堆内存分为新生代和老年代,新生代是用于寄存应用后筹备被回收的对象,老年代是用于寄存生命周期比拟长的对象。大部分咱们创立的对象,都属于生命周期比拟短的,所以会寄存在新生代。新生代又细分 Eden 空间、From Survivor 空间、To Survivor 空间,咱们创立的对象,对象优先在 Eden 调配。
随着对象的创立,Eden 残余内存空间越来越少,就会触发 Minor GC
,于是 Eden 的存活对象会放入 From Survivor 空间。Minor GC
后,新对象仍然会往 Eden 调配。
Eden 残余内存空间越来越少,又会触发Minor GC
,于是 Eden 和 From Survivor 的存活对象会放入 To Survivor 空间。
大对象间接进入老年代
在下面的流程中,如果一个对象很大,始终在 Survivor 空间复制来复制去,那很费性能,所以这些大对象间接进入老年代。能够用 XX:PretenureSizeThreshold 来设置这些大对象的阈值。
长期存活的对象将进入老年代
在下面的流程中,如果一个对象 Hello_A,曾经经验了 15 次 Minor GC
还存活在 Survivor 空间中,那他行将转移到老年代。这个 15 能够通过 -XX:MaxTenuringThreshold 来设置的,默认是 15。虚拟机为了给对象计算他到底经验了几次Minor GC
,会给每个对象定义了一个对象年龄计数器。如果对象在 Eden 中通过第一次 Minor GC 后依然存活,挪动到 Survivor 空间年龄加 1,在 Survivor 区中每经验过 Minor GC 后依然存活年龄再加 1。年龄到了 15,就到了老年代。
动静年龄判断
除了年龄达到 MaxTenuringThreshold 的值,还有另外一个形式进入老年代,那就是动静年龄判断:在 Survivor 空间中雷同年龄所有对象大小的总和大于 Survivor 空间的一半,年龄大于或等于该年龄的对象就能够间接进入老年代。
比方 Survivor 是 100M,Hello1 和 Hello2 都是 3 岁,且总和超过了 50M,Hello3 是 4 岁,这个时候,这三个对象都将到老年代。
空间调配担保
下面的流程提过,存活的对象都会放入另外一个 Survivor 空间,如果这些存活的对象比 Survivor 空间还大呢?整个流程如下:
- Minor GC 之前,虚构机会先查看老年代最大可用的间断空间是否大于新生代所有对象总空间,如果大于,则发动 Minor GC。
- 如果小于,则看 HandlePromotionFailure 有没有设置,如果没有设置,就发动 full gc。
- 如果设置了 HandlePromotionFailure,则看老年代最大可用的间断空间是否大于历次降职到老年代对象的均匀大小,如果小于,就发动 full gc。
- 如果大于,发动 Minor GC。Minor GC 后,看 Survivor 空间是否足够寄存存活对象,如果不够,就放入老年代,如果够放,就间接寄存 Survivor 空间。如果老年代都不够放存活对象,担保失败(Handle Promotion Failure),发动 full gc。