您的位置:首页 > 编程语言 > Java开发

Java垃圾收集算法

2017-04-01 17:36 176 查看
Java虚拟机垃圾收集算法一共分为四种:

标记-清除算法、复制算法、标记-整理算法、分代收集算法

1、标记-清除算法

这是一种最基础的算法。该算法分为“标记”和“清理”两个阶段:首先标记除所有要回收的对象,在标记完后统一回收所有被标记的对象,其标记过程与对象标记判定一致。

不足:

(1)效率问题,标记和清除两个过程效率都不高

(2)空间问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾回收动作。

2、复制算法

将可用内存按照容量划分成大小相等的两块,每次只使用其中的一块。当一块内存用完了,就将存活的对象复制到另一块上面,然后把已使用过的内存空间一次性清理掉。这样使得每次都是对整个半区进行内存回收,内存分配时就不考虑内存碎片等复杂情况,只要移动堆顶指针,按照顺序分配内存即可,实现简单,运行高效。只是内存的利用率不高,只有一半。

现在的商业虚拟机都采用该算法来回收新生代,新生代绝大部分对象都是“朝生夕死”,故不按照1:1的比例划分内存空间,而是划分一个较大的Eden空间和两块较小的Survivor空间,每次使用Eden和一个Survivor。当回收时,将这两个空间中的还存活着的对象一次性复制到另一个Survivor中,最后清理掉Eden和刚才使用过的Survivor空间。 HotSpot虚拟机默认Eden和Survivor大小比为8:1,只有10%的内存会被浪费掉。我们没有办法保证每次回收都只有不多于10%的对象存活,当Survivor空间不够用时,需要依赖其他内存(这里指老年代)进行分配担保。

3、标记-整理算法

标记过程跟“标记-清理算法”一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界意外的内存

4、分代收集算法

根据对象存活周期的不同将内存划分成几块。一般把Java堆分为新生代和老年代,在新生代中,每次GC都有大批对象死去,故采用复制算法;而老年代中因为对象存活率高,没有额外的空间对它进行担保,就必须使用“标记清理”或“标记整理”算法。

内存分配和回收策略

Java的自动内存管理可归结为自动化解决两个问题:给对象分配内存回收分配给对象的内存

1、对象有现在Eden区分配

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

2、大对象直接进入老年代

大对象:占用大量连续内存空间的Java对象,典型的为很长的字符串及数组。

经常出现大对象容易导致内存还有不少空间时就提前触发GC以获取足够的连续内存空间来安置它们。虚拟机提供了一个-XX: PretenureSizeThreshold参数,令大于该设置值的对象直接在老年代中分配,这避免了Eden去及两个Survivor区之间发生大量的内存复制

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

如果对象在Eden区出生并经过一次Minor GC仍存活,并能被Survivor区容纳的话,江北一道Survivor空间中,并且对象的年龄设为1.对象在Survivor区中没每熬过一次Minor GC年龄就加1岁,当增加到一定程度的时候(默认为15岁),将会被晋升到老年代中。对象晋升到老年代的年龄阈值,可通过参数-XX:MaxTenuringThreshold设置

4、动态对象年龄的判定

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

5、空间分配担保

在发生Minor GC 之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象的总空间,若成立即确保Minor GC是安全的。若不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。若允许则继续检查老年代最大连续可用空间是否大于历次晋升到老年代对象的平均代销,若大于,尝试Minor GC,尽管这次Minor GC 是有风险的;若小于,或HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  虚拟机 java