GC怎么判断对象死亡的

引用计数器算法

引用计数器算法是通过一个计数器来实现的:
- 给每个对象添加一个引用计数器
- 如果新增一个引用,那么引用计数器加一
- 如果失去一个引用,那么引用计数器减一
- 如果引用计数器等于零,那么理解为这个对象死亡

这就是引用计数器算法,实现简单并且判定效率高,但是这个算法存在一个致命的问题,会导致内存泄漏。先看下面的例子:

1    public class ReferenceCountAlgorithm {
2    
3        private Object instance;
4        
5        public static void main(String[] args) {
6            ReferenceCountAlgorithm objA = new ReferenceCountAlgorithm();
7            ReferenceCountAlgorithm objB = new ReferenceCountAlgorithm();
8            
9            objA.instance = objB;
10           objB.instance = objA;
11            
12           objA = null;
13           objB = null;
14            
15       }
16   }

在这个例子里面第一个new ReferenceCountAlgorithm()
- 这个对象在第6行添加了一个引用objA,引用计数器等于1
- 在第10行又添加了一个引用objB.instance,计数器等于2
- 在第12行失去了一个引用objA,引用计数器等于1

同样的第二个new ReferenceCountAlgorithm()对象最终引用计数器也是1。

此时这两个对象都无法被访问到了,但是他们的引用计数器都不是0,所以如果使用引用计数器算法,那么垃圾收集将不会回收这两个对象,从而导致内存泄漏。

可达性分析算法

目前主流的程序语言(Java、C#等)都是通过可达性分析算法来判断对象是否死亡,是否需要被回收的。

可达性算法是通过计算对象是否”可达”来实现的:
- 定义一系列的”GC Roots”作为根节点
- 从根节点开始往下搜索,搜索所走的路径叫做引用链
- 如果一个对象到任何一个根节点都没有引用链,那么判定为不可达

而只有以下几种对象可以作为”GC Roots”根节点:
- 虚拟机栈中引用的对象,也就是正在执行的方法中引用变量指向的对象
- 方法区中静态属性引用的对象,也就是类的静态成员变量引用的对象
- 方法去中常量引用的对象,主要指String和Class类型
- 本地方法栈中Native方法引用的对象

还是上面ReferenceCountAlgorithm类的案例,只有main方法执行结束,两个ReferenceCountAlgorithm对象都会失去引用链,从而被判断为死亡,无论这两个对象是否有互相的引用。

所以我们目前Java采用的判定对象死亡与否的算法就是可达性分析算法。

至于对象被判定为死亡之后,是否会立即被回收,这里的答案是否定的。

被判定为死亡的对象需要经历两次GC的扫描,还被认定为不可达的对象才会被回收,两次扫描的机制可以看一下上一篇文章finalize()方法总结


喜欢这篇文章的朋友,欢迎扫描下图关注公众号lebronchen,第一时间收到更新内容。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/Leon_cx/article/details/81911022
今日推荐