JVM内存回收策略

对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程有限分配在TLAB上。少数情况下也可能会直接分配在老年代。

内存分配策略:

对象优先在Eden分配

大多数情况情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。
注:新生代GC(Minor GC):指发生在新生代的垃圾收集动作,因为Java队形大多都是具备朝生夕死的特性,所以MinorGC非常频繁,一般回收速度也比较快。(新生代采用复制收集算法。)
老年代GC(Major GC/Full GC):指发生在老年代的GC,出现Major GC,至少会伴随至少一次Minor GC。Major GC 一般会比Minor GC慢 10 倍以上。(复习:Full GC,采用标记——清除,或者标记——整理算法。)
例子:10M新生代,10M老年代,新生代中Eden区与一个Survivor区的空间比例是8:1,新生代可用空间为(Eden区+1个Survivor区=9M)。
程序按顺序分别分配3个2M对象,1个4M对象。在对第4个对象分配的时候会发生一次Minor GC,因为第4个对象4M剩余Eden区不足以分配,所以通过分配担保机制提前转移到老年代去。借此GC结束以后,4MB对象顺利分配在Eden中,Survivor空闲,老年代被占用6MB。

大对象直接进入老年代

大对象指大量需要连续内存空间的Java内存,典型如很长的字符串和数组。更糟糕的是有”朝生夕灭“的”短命大对象“,写程序的时候尽量避免。
可以设置对象大于某个值直接在老年代分配。-XX:PrentenureSizeThreshold参数。
目的是为了避免Eden区及两个Survivor区之间发生大量大的内存复制。

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

内存回收能识别哪些对象应放在新生代,哪些老年代。虚拟机给每个对象定义一个对象年龄(Age)计数器。在Eden出生并经过一次Minor GC后依然存活,并且能被Survivor容纳就移动到Survivor空间中,并且对象年龄设为1.对象在Survivor区中每”熬过“一次Minor GC,年龄就增加1岁,而它的年龄增加到一定程度(默认为15岁),就将它晋升到老年代中。年龄阈值可以设置–XX:MaxTenuringThreshold。

动态年龄判定

为了更好适应不同程序的内存状况,虚拟机并不是永远地要求对象的年龄必须达到设定的阈值MaxTenuringThreshold才能晋升到老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold要求的年龄了。

空间分配担保

在发生Minor GC之前,虚拟机会检查老年代最大可用连续空间是否大于新生代所有对象总空间,如果成立,那么Minor GC可以确保是安全的。如果不成立,则虚拟机查看HandlePromotionFailure设置值是否允许晋升到老年代对象的平均大小,如果大于,将尝试着进行一次Minor GC。尽管这次Minor GC是有风险的;如果小于,或者HandlePromotionFailure设置不允许冒险,那这时候也要该位进行一次Full GC。

你可能感兴趣的:(java虚拟机)