Java内存分配与回收策略

Java对象的内存分配其实就是在堆上分配,对象主要分配在新生代的Eden区,如果启动了本地线程分配缓冲,则按线程优先分配在TLAB上。少数的情况会直接分配到老年代中。几点规则和总结。

Minor GC与FULL GC

新生代GC(Minor GC):指发生在新生代的垃圾回收,因为大多Java对象具有朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也非常快。
老年代GC(Major GC/FULL GC):指发生在老年代的GC,Major GC速度一般会比Minor GC慢十倍以上。

对象优先分配在Eden区

大多数情况下,对象在新生代的Eden区分配,当Eden区没有足够的空间时候,虚拟机会发起一次Minor GC。

大对象直接进入老年代

大对象是指需要大量连续内存空间的Java对象,典型的大对象是那种很长的字符串以及数组。虚拟机提供了几个-XX:PretenureSizeThresHold参数,令大于这个值的对象直接在老年代分配。目的是避免在Eden区以及两个Survivor区之间发生大量的内存复制(新生代的垃圾回收采用了复制算法)。

长期存活的对象将进入老年代

Java虚拟机采用了分代收集的思想来管理内存,虚拟机通过给每个对象定义一个对象年龄计数器来标识哪些对象应该放在新生代,哪些对象应该放在老年代。如果对象在Enen区出生并经过第一次Minor GC后任然存活,并且能被Surivior容纳话,该对象将被移动到Surivior空间中并将对象年龄设为1;对象在Surivior区中每经过一次Minor GC并存活年龄就将增加1岁,当年龄增加到一定程度(默认15岁),就会将该对象移动到老年代中。

空间分配担保

在发生Minor GC之前,虚拟机会检查老年代的最大可用连续空间是否大于新生代所有对象总空间,如果条件成立则Minor GC是安全的。如果不成立,则虚拟机会查看HeandlePromotionFailure的设置值是否允许担保失败。如果允许,那么继续检查老年代的最大可用连续空间是否大于新生代历次晋升到老年代对象的平均大小,大于,则将尝试一次Minor GC。如果小于或者HeandlePromotionFailure不允许冒险,则需要进行一次FULL GC。


gc