JVM进阶之GC(三)垃圾回收算法

上篇我们讨论了怎么判断对象是否存活,判了“死刑”的对象就会在垃圾回收中被回收掉。那么本文将说说JVM是如何回收垃圾的。

垃圾回收算法

标记-清除算法

算法的过程就如同算法的名字,分为标记清除两个阶段:首先标记出所有要回收的对象,然后对标记的对象统一清除。算法很简单,再看下逻辑图: 
标记清除过程 
内存空间经过标记清除算法回收的过程一目了然,从图中也能看出这种算法的不足,即标记清除后会产生大量的不连续的内存碎片,如果碎片过多会导致大对象无法分配足够的空间而不得不触发垃圾回收。 
另外,标记清除算法的标记和清除阶段效率都不高,所以效率也是个问题。

复制算法

既然标记清除效率达不到预期,那么新的回收算法就被创造出来了–复制算法。算法将可用内存分成两块大小一样的区域,每次只使用其中的一块区域,当使用的区域空间不足时就得进行垃圾回收了,而存活的对象就直接转移至另一块区域,如此往复。看如下复制算法逻辑图: 
复制算法
每次垃圾回收都是在一块区域进行,即一半的空间进行内存回收。好处是内存分配后不会产生内存碎片问题,当然缺点也显而易见,内存空间利用率只有一半。 
由于每次垃圾回收需要对存活对象再一次迁移,这种算法适用于存活对象较少的场景。根据大多数经验表明,新生代的对象98%都是朝生熄灭的,所以复制算法适应于新生代的垃圾回收。但是在新生代中,一半的空间利用率实在太低,而且绝大部分对象都会被回收的特性,所以将内存分为了较大的eden区和两个较小的survivor区(s0和s1区),每次使用eden区和其中的一个survivor区,另一个survivor区则用于保存存活的对象。HotSpot虚拟机默认eden和survivor的比例是8:1,也就是说空间利用率达到了90%(80%+10%)。

标记-整理算法

顾名思义,看名字大致与标记-清除算法类似,其算法的标记过程还真是一样,但后续不是直接清除垃圾对象,而是让所有的存活的对象向一个方向移动,然后再清理掉存活对象边界之外的内存空间。来看图更清晰: 
标记整理算法 
上图与标记清除算法的图一比较就很容易发现区别了,标记整理算法重在整理。 
那么标记整理算法相对于复制算法有什么优势呢?复制算法,在回收对象存活率低的情况下比较合适,如果在对象存活率较高时(比如老年代的垃圾回收),就要进行较多的复制操作,效率明显变低,所以不会采用复制算法。而在对象存活较高的区域中,如老年代,采用标记整理算法是比较合适的。

分代收集算法

在前面内存分代的文章中说过,堆中根据对象的存活时间划分为新生代、老年代和永久代几个区域,这里又可以根据各个年代的特点采用最合适的垃圾回收算法。新生代绝大部分对象朝生熄灭,只有少部分存活,采用复制算法最合适不过。老年代对象即使进行了垃圾回收,对象的存活率也高,所以采用标记清除或标记整理算法都是不错的选择。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值