jvm如何判断对象是否可以回收或存活

众所周知,Java将程序员从内存管理中解放出来,使得我们在编写代码的时候不用手动的分配和释放内存,内存管理的任务由JVM承担起来。本文就将讲解JVM在回收对象之前,如何判断一个对象是否应该被回收。

在此之前,我们先来复习一个和Java对象回收有关的知识,那便是finalize方法,这是一个在Object类中定义的方法,如果我们重写了finalize方法,那么在对象被回收之前将会调用finalize方法,如果我们在finalize方法中将对象和某个还在生命周期的对象关联上,那么这个对象还有可能在回收之前被复活,当然这种机会只有一次,当第二次遇到回收时,将不会再调用finalize方法。

下面我们正式介绍Java对象是否存活的判断算法——根搜索算法。这个算法的思路其实很简单,它把内存中的每一个对象都看作一个节点,并且定义了一些对象作为根节点“GC Roots”。如果一个对象中有另一个对象的引用,那么就认为第一个对象有一条指向第二个对象的边,如下图所示。JVM会起一个线程从所有的GC Roots开始往下遍历,当遍历完之后如果发现有一些对象不可到达,那么就认为这些对象已经没有用了,需要被回收。

jvm如何判断对象是否可以回收或存活

根搜索算法图解

这个算法的关键就在于GC Roots的定义,教科书中给出了四种作为GC Roots的对象,

首先第一种是虚拟机栈中的引用的对象,我们在程序中正常创建一个对象,对象会在堆上开辟一块空间,同时会将这块空间的地址作为引用保存到虚拟机栈中,如果对象生命周期结束了,那么引用就会从虚拟机栈中出栈,因此如果在虚拟机栈中有引用,就说明这个对象还是有用的,这种情况是最常见的。

第二种是我们在类中定义了全局的静态的对象,也就是使用了static关键字,由于虚拟机栈是线程私有的,所以这种对象的引用会保存在共有的方法区中,显然将方法区中的静态引用作为GC Roots是必须的。

第三种便是常量引用,就是使用了static final关键字,由于这种引用初始化之后不会修改,所以方法区常量池里的引用的对象也应该作为GC Roots。

最后一种是在使用JNI技术时,有时候单纯的Java代码并不能满足我们的需求,我们可能需要在Java中调用C或C++的代码,因此会使用native方法,JVM内存中专门有一块本地方法栈,用来保存这些对象的引用,所以本地方法栈中引用的对象也会被作为GC Roots。

转自:

https://blog.****.net/weixin_28760063/article/details/81271827