浅谈Java垃圾回收

Posted by 李小武 on February 25, 2011

垃圾回收,是java同c++的一个重大区别,也是编写java程序不用指针的一个重要保证。在c++中,当一个对象不再有价值的时候,我们需要手动的清除这个对象,以释放空间。在java中,这个工作由垃圾回收器自动完成,程序员不必考虑难缠的对象回收问题。

一、垃圾回收的好处:

垃圾回收使程序员从释放内存的重担中解脱,可以把更多的精力放在编程和逻辑上,提高了效率。

垃圾回收保证了程序的正常运行,不会出现如c++中的因为对象忘记释放而产生的内存泄露等诸多问题。

二、垃圾回收的基本方法:

所有的垃圾回收算法都要做两件事:检测出垃圾对象和删除垃圾对象并把堆空间归还程序。

1.引用计数器:

在堆中的每个对象都有一个对应的计数器,当创建一个对象并将此对象的引用指定到一个变量的时候,引用计时器为1。当此对象被其他对象引用的时候,计数器+1,其他对象对此对象的引用取消,计数器-1。当计数器为0的时候,这个对象就已经是没有被引用的了,垃圾回收器就可以收集它了。

引用计数器被用在早期的垃圾回收策略中,计数器不能处理循环引用(父对象引用子对象,自对象也引用父对象,这两个对象采用引用计数器不能被收集)。

2.跟踪收集器:

跟踪收集器将堆中的对象及引用映射成一个图。对象为图的节点,对象间的引用为图中的边。

垃圾回收从跟节点开始,通过历遍这个图找出图中的孤立节点,即为垃圾对象。

三、垃圾回收处理堆碎块的策略:

当一个对象被回收后,它的堆空间归还程序,当对个对象被回收后,就会出现一个问题,堆中的空间不连续了。如此,当创建一个新对象的时候,可能由于堆中前面的空白空间不够而不得不继续分配后面连续的空间,这样不仅浪费堆空间,而且可能造成对空间不足,内存溢出。

一般情况下,采用以下几种回收器来解决这个问题:

1.压缩收集器:

压缩收集器把活动的对象移动到堆的一段,那么在堆的另一端就好出现连续的大片空白空间。

image

2.拷贝收集器:

拷贝收集器将活动对象拷贝到一个新的区域,在拷贝过程中,这些活动的对象将被紧凑的放在新的区域,这样就消除了旧区域的空隙。当新区域满的时候,再将活动对象拷贝到旧区域,如此往复。

由于对象拷贝需要程序停止运行,区域中对象的拷贝很耗时,会影响程序的正常运行。

before copy:

image

after copy:

image

3.按代收集器:

在程序中大对象有这样的特点,大部分对象的生命周期比较短,小部分的对象生命周期比较长。考虑到这个原因,可以把堆分成若干个子堆,每个子堆称为一代(由低到高一代,二代三代……)。把生命周短的对象放在底代中,生命周期长的放在高代中。这样,底代的对象收集会更频繁一点,高代的则收集频率少一点,保证了收集的效率。在每次收集的时候,如果发现这个代中的对象是活动的,则把它放到更高的代中,否则收集。

4.自适应收集器:

自适应收集会根据堆中的对象情况选择适当的收集器或调整收集器的参数,以实现更高的效率。 以上即是java垃圾回收的基本方法。如有不足和错误欢迎大家指正。