Java垃圾回收算法

此篇文章主要借鉴《深入理解Java虚拟机》和《Thinking in Java》

前提概要

Java垃圾回收机制主要有两个方面,一是垃圾回收算法,二是垃圾回收器。此篇文章主要介绍垃圾回收算法。

主要的垃圾回收算法如下:
1、引用计数算法
2、标记-清扫算法
3、复制算法
4、标记-整理算法
5、分代收集算法

查找可存活对象的方法

除了引用计数算法外,其他的算法都需要查找可存活的对象,其方式主要如下:
1、使用遍历的方式,遍历“栈中的局部变量的引用”和“方法区中的常量和静态变量的引用”。
2、堆中被引用的对象就是存活的对象。

引用计数算法

堆中的每个对象有一个引用计数器(初始值为0),当有引用连接对象的时候,引用计数器加1。垃圾回收器开始作用的时候,会在堆中遍历,把引用计数为0的对象都释放。

缺陷

无法释放循环引用的对象。
比如有两个类Student和Teacher。Student中有对Teacher的引用,而Teacher中也有对Student的引用。
分别新建了两个对象s和t。s中有对t的引用,而t中有对s的引用。
那么当我不使用s和t这两个引用的时候,这两个对象还是实际存在的,并且他们之间互相引用,所以无法释放。

标记-清扫算法

找出堆中所有存活的对象,每找到一个存活的对象,就会给对象设一个标记,这个过程不会回收任何对象。只有当全部标记工作完成的时候,清理动作才会开始。在清理过程中,没有标记的对象会被释放。

缺陷

所剩下的堆控件是不连续的,产生了大量不连续的内存碎片,空间碎片太多可能会导致在程序运行过程中要分配较大的对象的时候,无法找到足够的连续内存而不得不提前出发垃圾收集动作。

复制算法

将堆的容量划分为大小相等的两块,每次只使用其中的一块。当执行垃圾回收的时候,就把当前堆中存活的对象复制到另一个堆中,然后清空这个使用过的堆,这样就只保留了存活的对象。
使用复制算法就不需要考虑内存碎片的情况,只要移动堆中的指针,按顺序分配内存即可,实现简单,运行高效。

缺陷

1、代价很大,相当于将可以使用的内存缩小为了原来的一半。
2、如果触发垃圾收集操作的时候,堆中只有少量的垃圾,甚至没有垃圾。复制操作还是会把所有存活的对象都复制一遍,这会浪费资源。

标记-整理算法

找出堆中所有存活的对象,每找到一个存活的对象,就会给对象设一个标记。让所有存活的对象移动到内存的一端,然后直接回收掉端边界以外的其他对象。(移动的过程不回收对象)

分代收集算法

根据对象的存活周期不同将内存划分为新生代和老年代,存活周期短的为新生代,存活周期长的为老年代。这样就可以根据每块内存的特点采用最适当的收集算法。
新生代的中每次垃圾收集中会发现有大批对象死区,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。
老年代中因为对象的存活率高,没有额外的控件对它进行分配担保,就必须使用“标记-清扫”或者“标记-整理”算法来进行回收。

你可能感兴趣的:(【Java】)