时间:2021-05-20
java垃圾回收算法之-引用计数器,这个算法其中一个优点便是,实时性,只要对象的引用计数器的值为0,则立刻回收。接下来介绍的标记清除算法,当对象的引用计数器的值为0时,不会立刻被回收的。
概念介绍
root对象
在标记清除算法中,会把如下对象称之为root对象
可访问的对象
如果栈中有一个变量a引用了一个对象,那么该对象是可访问的,如果该对象中的某一个字段引用了另一个对象b,那么b也是可访问的。可访问的对象也称之为live对象
标记清除算法介绍
该算法有两个阶段。
1. 标记阶段:找到所有可访问的对象,做个标记
2. 清除阶段:遍历堆,把未被标记的对象回收
备注:
标记阶段算法
伪代码类似如下:
for each root variable r mark (r);sweep ();为了能够区分对象是live的,可以为每个对象添加一个marked字段,该字段在对象创建的时候,默认值是false
假设有一个对象p,p对象还间接的引用了其他对象,那么可以使用一个递归算法去进行标记,例如:
void mark(Object p) if (!p.marked) p.marked = true; for each Object q referenced by p mark (q);这个mark方法只有当所有对象已经被mark后才会退出。
清除阶段算法
在这个阶段,需要去遍历堆中所有对象,并找出未被mark的对象,进行回收。与此同时,那些被mark过的对象的marked字段的值会被重新设置为false,以便下次的垃圾回收。
伪代码如下:
void sweep () for each Object p in the heap if (p.marked) p.marked = false else heap.release (p);下面用一张图来表示标记清除算法的整个过程。
标记清除算法的优点和缺点
1. 优点
- 是可以解决循环引用的问题
- 必要时才回收(内存不足时)
2. 缺点:
- 回收时,应用需要挂起,也就是stop the world。
- 标记和清除的效率不高,尤其是要扫描的对象比较多的时候
- 会造成内存碎片(会导致明明有内存空间,但是由于不连续,申请稍微大一些的对象无法做到),如下图:
解决循环引用
出现循环引用的代码如下:
class TestA{ public TestB b;}class TestB{ public TestA a;}public class Main{ public static void main(String[] args){ A a = new A(); B b = new B(); a.b=b; b.a=a; a = null; b = null; }}对应的图如下:
这个时候,当a = null; b = null;的时候,图像变成如下:
那么使用标记清除算法是可以回收a和b的,原因是标记清除算法是从栈中根对象开始的,改算法走完后,a对象和b对象是没有被标记的,会被直接回收。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
之前写过的一篇Java垃圾回收之标记清除算法详解,这个算法有个缺点就是造成内存碎片,存在不连续的空间,这样会导致申请较大空间的时候,又需要进行垃圾回收。下面介绍
之前的Java垃圾回收之标记清除算法详解会导致内存碎片。下文的介绍的coping算法可以解决内存碎片问题。概述如果jvm使用了coping算法,一开始就会将可用
Java垃圾回收与对象生命周期详解Java中的垃圾回收与对象生命周期1.垃圾回收垃圾回收是Java程序设计中内存管理的核心概念,JVM的内存管理机制被称为垃圾回
在进行老生代的标记清除法回收以前,还会有一个新生代的垃圾回收算法执行。新生代和老生代所谓新生代,指的是新产生的对象;老生代就是经历过新生代垃圾回收后还“存活”下
JVM中常见的垃圾收集算法有四种:标记-清除算法(Mark-Sweep);复制算法(Copying);标记-整理(Mark-Compact);分代收集;下面我们