JVM的垃圾回收策略

1.标记-清除算法:

算法分两个阶段:标记和清除阶段,首先会标记出所有需要回收的对象,在标记完后统一回收所有被标记的对象,它是最基础的垃圾回收算法。因为后续的垃圾收集算法主要基于这种思路对其不足进行改进。它的不足有两个:一个是效率问题,标记和清除两个过程效率都不高,另一个是空间问题,标记清除后产生大量的不连续的空间碎片,太多的碎片导致以后在程序运行过程分配较大的对象时候因为找不到足够大的内存而不得不提前触发另一次的垃圾回收动作。

2.复制算法

为了解决标记清除效率问题,复制算法就出现,它把内存容量分成两等份,每次只使用其中一块,当这一块内存用完之后,就将存活的对象复制到另一块内存上去,然后把已使用的内存空间一次清理掉,这样使得每次都对整个半区进行回收,内存分派也不用再考虑碎片的情况,只需堆顶指针移动,按顺序分配即可。但算法的代价是把内存缩成一半,成本太高。堆内存中的新生代一般采用这方法回收,将内存分为Eden和两块较小的Survior空间,比例为8:1,每次只使用Eden和Survior0,当回收时候,将Eden和Survior0的存活对象复制到Survior1上,最后清理Eden和Survior0的空间。当Survior空间不够用时,需要依赖其他内存(老年代)进行分配担保。

3.标记整理算法

复制算法在对象存活率比较高时候就要进行多复制的操作,效率会比较低,更关键是,如果另一块内存不够,就要使用分配担保机制,以应对所有对象100%存活的极端情况,因此老年代不能直接用这种算法。

根据老年代的特点,有人提出标记整理算法,标记过程跟标记清除一样,但后续步骤不是直接对对象的回收,而是让存活对象都向一端移动,然后清理掉端边的以外的内存。

4.分代收集算法

当前虚拟机都采用分代收集算法,这种算法并没什么的新的思想,只是根据对象存活周期不同将内存划分为几块,一般是把JAVA堆分为新生代和老年代,这样根据各个年代的特点采用适当的算法,在新生代中发现有大批对象死去,少量存活,则采用复制算法,只需要复制少量存活对象就可以完成收集,而老年代因为对象存活率较高,没有额外的空间再对它进行分配担保,就必须采用标记-清除或者标记-整理算法来回收。

那么如何判断一个对象是否能回收呢?

引用计数算法:

给一个对象中添加一个引用计数器,每当有一个地方引用它时候计数器+1,当引用失效时候计数器减一,当计数器为0时候就是不能在使用,也就是可以回收的对象,但如果存在相互引用的话,这种方法就容易失效。

可达性算法:

主流的虚拟机都是通过可达性算法判断对象是否存活的,通过一些列GC ROOTS的对象为起点,从这些起点向下搜索,搜索过的路为引用连,当一个对象到GC ROOTS没有任何引用链时候,则表示这个对象是不可用的

在JAVA中作为GCROOTS对象有:

a.虚拟机栈中引用的对象

b.方法区中静态属性引用的对象。

c.方法区中常量引用的对象

d.Native方法中JNI引用的对象。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值