垃圾收集算法

 垃圾收集

Java的一大特点就是可以进行自动垃圾回收处理。自动垃圾回收减轻了开发人员的工作量,但增加了系统的负担。

1、引用计数法

引用计数法是最经典也是最古老的一种垃圾收集方法。对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器+1,当引用失效后,引用计数器-1。只要对象A的引用计数器的值为0,则说明对象A已经不会再被使用,可以进行垃圾回收。

引用计数法的实现比较简单,只需要为美俄对象配备一个整形的计数器即可。但是引用计数器有一个严重的问题,即无法处理循环引用的情况,所以Java中没有使用引用计数法。


如图,A引用B,B引用A,A和B的引用均为1,但是除了A与B,没有其他任何对象引用A或B,则此时可认为A跟B应该进行垃圾回收。

2、标记-清除算法 

标记-清除算法是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。

标记阶段:

通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。

清除阶段:

清除所有未被标记的垃圾对象。

标记-清除算法可能产生的最大问题就是空间碎片。

 

那么,怎么确定根节点呢?在Java中可以作为GC Roots的对象:

1、虚拟机栈(左上)的栈帧的局部变量表所引用的对象

2、本地方法栈(右中)的JNI所引用的对象

3、方法区(右下)的静态变量和常量所引用的对象

 

 回收后的空间是不连续的,在给对象分配内存时,尤其是大对象,不连续的内存空间工作效率要低于连续的内存空间。

3、复制算法

复制算法相对高效于标记-清除算法。核心思想是:将原有的内存空间分成两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到另一块未使用的内存块,清除正在使用的内存块对象。

所以当内存中的存活对象越少,所需要复制的对象也越少,算法效率越高。复制后的内存空间为连续的内存空间,所以不会产生空间碎片。复制算法使系统内存折半。

 

 Java的新生代串行垃圾回收器使用了复制算法。新生代又eden去,from区(s0),to区(s1)组成。from区和to区也成Survivor空间,即幸存者空间,用于存放未被回收的对象。from区和to区就使用到了复制算法。

复制算法比较适合用于新生代,因为新生代中的垃圾对象一般都会多余存活对象。

4、标记-压缩算法

标记-压缩算法是老年代的一种回收算法。它在标记-清除算法的基础上做了一些优化。标记-压缩法从根节点开始,对所有可达对象做标记,然后清理垃圾对象,接着将活着的对象压缩到内存一侧,避免碎片产生。


5、增量算法

 增量算法的基本思想是,如果一次性将所有的垃圾进行处理。需要造成系统长时间的停顿,那么就可以将垃圾收集线程和应用程序线程交替进行。每次垃圾收集线程至收集一小片内存空间。接着切换到应用程序线程。以此反复,直到垃圾收集完成。使用这种方式,由于在垃圾回收的过程中,间断性地还执行了应用程序代码,所以能减少系统的停顿时间。但是,因为线程切换和上下文转换的消耗,会使得垃圾收集的总体成本上升,造成系统吞吐量下降。

6、分代

分代是将内存区间根据对象的特点分成几块,根据每块内存区间的特点,使用不同的回收算法,以提高垃圾回收效率。

以HotSpot虚拟机为例,它将所有的新建对象都放入到年轻代的内存区间,年轻代的特点是对象存活率低,容易被回收。因此,年轻代可以选择效率较高的复制算法。当对象经过几次回收后依然存活,对象会被放入到老年代的内存区间,在老年代中,几乎所有的对象都是经过几次垃圾回收后依然存活的对象,因此,可以认为这些对象在一段时间,甚至在应用程序的整个生命周期中常驻内存。根据老年代的特点,可以选择标记-压缩算法以提高垃圾回收效率。



 

 

 

参考:

《Java程序性能优化  让你的Java程序更快、更稳定》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值