内存分配与回收策略

相关概念:

Eden区和survivor区:现在的商业虚拟机大多采用复制算法来回收新生代,但大多数新生代中的对象存活时间比较短,所以每次GC后剩下的存活对象并不多,因此不需要按照1:1的比例来划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次只使用Eden和其中一块Survivor空间,回收时将这两块空间中存活的对象复制到另一块Survivor空间上,然后清理掉Eden和刚刚用过的Survivor空间。HotSpot虚拟机默认的Eden和Survivo的大小比例是8:1,当Survivor空间不足时,需要依赖其它内存(老年代)进行分配担保

新生代GC(Minor GC):发生在新生代的代的垃圾回收,非常频繁且回收速度快

老年代GC(Major GC/Full GC):发生在老年代的GC,速度比Minor GC至少慢十倍

普遍的内存分配规则:

(1)对象优先在Eden分配:大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够的空间进行分配时,虚拟机将发起一次Minor GC

(2)大对象直接进入老年代:大对象就是需要大量连续内存空间的Java对象,如很长的字符串以及数组等,经常出现大对象容易导致内存还有不少空间时就要提前触发垃圾收集装置以获取足够的连续空间来安置它们,所以虚拟机提供了一个参数,另大于这个设置值的对象直接在老年代分配

(3)长期存活的对象将进入老年代:虚拟机给每个对象定义了一个对象年龄(Age)计数器,对象经过第一次Minor GC后会被放入Survivor区,年龄为1,然后经过每一次Minor GC并且存活下来的话,年龄就增加一岁,增加到一定值时就会被晋升到老年代,这个值有使用者设置,默认为15岁

(4)动态对象年龄判断:虚拟机不是要求对象的年龄必须达到所设置的值才能晋升老年代,如果在Survivor区中同年龄的所有对象大小总和大于Survivor空间的一半,则年龄大于或等于该年龄的对象可以直接进入老年代

(5)空间分配担保:在Minor GC之前,虚拟机会先检查老年代最大可用连续空间是否大于新生代所有对象大小总和,如果是,那么Minor是安全的;如果不是,这虚拟机会查看HandlePromotionFailure设置值是否允许担保失败,如果允许,那么会继续检查老年代最大可用连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,则会冒险进行一次Minor GC,但这次Minor是有风险的,因为当晋升到老年代的对象总空间大于老年代可用连续空间时,就会担保失败,然后进行一次Full GC;如果小于,或者HandlePromotionFailure设置为不允许,这时就要进行一次Full GC了。虽然担保失败之后进行的Full GC耗时最长,但是为避免Full GC过于频繁,大部分情况还是会将HandlePromotionFailure开关打开。JDK6 Update 24之后不再使用HandlePromotionFailure参数,改为只要老年代最大可用连续空间大于新生代所有对象大小总和或者历次晋升到老年代对象的平均大小,就会进行Minor GC,否则进行Full GC

你可能感兴趣的:(内存分配与回收策略)