JVM GC:如何确定一个对象是否可以被回收

前言:

众所周知,java引入了垃圾回收机制(GC),将程序员比较头疼的内存管理问题轻松加愉快的解决了。我们不用再关心程序什么时候去释放内存,什么时候去回收内存了,那么GC是怎么判断程序中的对象是不是一个垃圾,要不要回收的呢?

引用的概念:

简单的理解,如果一个变量的类型是 类类型,而非基本类型,那么该变量又叫做引用,类类型创建的对象都可以称为引用。

引用计数:

上面讲过了什么是引用,其实 java在GC时也会去看这个对象有没有任何引用与之关联,如果存在引用关系则表示这个对象还有用,不能被回收,如果不存在引用则可以基本定性为可被回收的对象了。使用此方式效率确实很高,但是有个致命的缺点,无法解决循环引用的问,例如下面这段代码:

public class Main {
    public static void main(String[] args) {
        MyObject object1 = new MyObject();
        MyObject object2 = new MyObject();
        object1.object = object2;
        object2.object = object1;
        object1 = null;
        object2 = null;
    }
}
 
class MyObject{
    public Object object = null;
}

可以看到将object1和object2赋值为null,也就是说object1和object2指向的对象已经不可能再被访问,但是由于它们互相引用对方,导致它们的引用计数都不为0,那么垃圾收集器就永远不会回收它们。因此在Java中并没有采用这种方式。

正向可达:

为了解决循环引用的问题,java中采取了正向可达的方式,主要是通过Roots对象作为起点进行搜索,搜索走过的路径称为“引用链”,当一个对象到 Roots 没有任何的引用链相连时时,证明此对象不可用,当然被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就真的成为可回收对象了,能否被回收其实主要还是要看finalize()方法有没有与引用链上的对象关联,如果在finalize()方法中有关联则自救成功,该对象不可被回收,反之如果没有关联则成功被二次标记成功,就可以称为要被回收的垃圾了。
Roots对象:
面试常问的问题,Roots对象有哪些?
1、引用栈帧中的本地变量表的所有对象;
2、引用方法区中静态属性的所有对象;
3、引用方法区中常量的所有对象;
4、引用Native方法的所有对象。

发布了87 篇原创文章 · 获赞 32 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/breakout_alex/article/details/105470758