深入理解JVM(四)——如何判定对象为垃圾对象

1.引用计数法

2.可达性分析算法

3.谈一谈GCRoot

在堆里面存放着JAVA世界中几乎所有的对象实例,垃圾收集器在对堆对象进行回收以前,第一件事情就是要确定这些对象之中哪些还“存活”着,哪些已经“死去”。

1.引用计数法
引用计数法就是一种判定该对象是否为垃圾对象的方法,它是这么做的:在每个对象中添加一个引用计数器,当有地方引用这个对象的时候,引用计数器就+1,当引用失效的时候,计数器的值就-1。任何时刻计数器为0的对象就是不可能再被使用的。
这种方法是一个不错的算法,而且非常容易实现,但是JAVA虚拟机却没有选用引用计数法来管理内存,其中最主要的原因是因为它很难解决对象之间相互循环引用的问题。

举个简单的例子

        ReferenceCountingDemo obj1 = new ReferenceCountingDemo();
        ReferenceCountingDemo obj2 = new ReferenceCountingDemo();
        obj1.instance = obj2;
        obj2.instance = obj1;

        obj1 = null;
        obj2 = null;

此时我们可以看出,obj1和obj2已经没有引用对象了,但是他们的实例属性instance还引用这对象,这种情况下,它们各自的计数器的值还是1,因此,这种方法很难解决对象之前循环引用的问题。

2.可达性分析算法
目前的JAVA虚拟机是使用可达性分析算法来判定对象是否存活的,这个算法的基本思路就是通过一系列被称为(GCRoot)的对象作为起始点(什么是GCRoot我们下文再谈),从这些节点开始向下搜索,搜索所走过的路径成为引用链,,当一个对象没有任何引用链相连,则证明此对象是不可用的,回收。

深入理解JVM(四)——如何判定对象为垃圾对象_第1张图片

3.谈一谈GCRoot
上文我们提到过可达性分析算法通过GCRoot开始搜索,那么有哪些对象可以当做GCRoot?
a. java虚拟机栈中的引用的对象。
b.方法区中的类静态属性引用的对象。 (一般指被static修饰的对象,加载类的时候就加载到内存中。)
c.方法区中的常量引用的对象。
d.本地方法栈中的JNI(native方法)引用的对象

接下来我们就对上述四种情况做一个分析:

a. java虚拟机栈中的引用的对象。

我们都知道,java虚拟机在调用方法的时候都会创建一个相应的栈帧,栈帧中包含了这个方法内部使用的所有对象的引用,一旦方法执行结束之后,这些临时对象引用也就不复存在了,这些对象就会被垃圾收集器给回收。

b.方法区中的类静态属性引用的对象。 (一般指被static修饰的对象,加载类的时候就加载到内存中。)
这个没什么好解释的, 就是被static修饰的对象,多用于单例模式的写法。

c.方法区中的常量引用的对象。
也就是被final修饰的对象。

d.本地方法栈中的JNI(native方法)引用的对象

最后,真的要宣告对象死亡需要经过两个过程
1.可达性分析后没有发现引用链
2.查看对象是否有finalize方法,如果有重写且在方法内完成自救(如再建立引用),还是可以抢救一下。

你可能感兴趣的:(javajvm垃圾回收机制)