概述:
Java 自动内存管理最核心的功能是 堆 内存中对象的分配与回收。java堆是垃圾收集器管理的主要区域,现在垃圾收集器大多采用分代垃圾回收算法。所以 Java 堆还可以细分为:新生代和老年代:再细致一点有:Eden 空间、From Survivor、To Survivor 空间等。进一步划分的目的是更好地回收内存,或者更快地分配内存。
在大多数情况下,对象首先会在Eden区分配,当Eden区空间不足时,会进行一次Minor GC,每次执行Minor GC,Eden和From Survivor存活下来的对象会进到To Survivor(对象在To Survivor空间不足时直接进入老年代),此时再将 From Survivor和To Survivor角色互换(这样就能保持To Survivor区始终为空),重复上面的操作。每一次Minor GC,存活下来的对象年龄都会加1,当对象年龄超过指定阈值时,将进入老年代。当老年代空间满时,就会进行一次Major GC(由于Major GC常常伴有Minor GC,故也可看作是一次Full GC)。
总结起来,堆内存常见的分配策略有三种,如下图:
图片来源:https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/jvm/JVM%E5%9E%83%E5%9C%BE%E5%9B%9E%E6%94%B6.md
-
对象优先在Eden区分配
一般情况下,对象优先在Eden去分配,当Eden区空间不足时,会触发一次Minor GC,存活下来的对象年龄加1。 -
大对象直接分配到老年代
大对象就是需要大量连续内存空间的对象(比如:字符串、数组)。为了避免为大对象分配内存时由于分配担保机制(新生代无法分配内存的时候,把新生代的对象转移到老生代,然后把新对象放入腾空的新生代)带来的复制而降低效率。 -
长期存活对象进入老年代
当对象的年龄增加到一定程度(默认为 15 岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。 -
动态对象年龄判定
Hotspot遍历所有对象时,按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了survivor区的一半时,取这个年龄和MaxTenuringThreshold中更小的一个值,作为新的晋升年龄阈值