![6390f266358a08ae7ac34a60a401d67d.png](https://i-blog.csdnimg.cn/blog_migrate/0a166e0945630156ca194906a28964ec.jpeg)
在Java中,我们经常需要去实例化一个对象,然后通过一个引用变量去获取这个对象,又或是直接创建一个匿名对象来使用。那么你是否知道,这个对象在内存中会经历些什么呢?
1. 三种状态
public class Test {
public static void main(String[] args) {
Test test = new Test();
}
}
当我们每一次new一个对象时,就会在堆区中占用一块内存,产生一个地址值,然后通过引用变量来获取到这个地址值,该引用通过这个地址值就可以找到堆区中的对象并对其进行操作。上面代码可以通过下图来看
![67e04364ea85ca08455dc35ace93c5d6.png](https://i-blog.csdnimg.cn/blog_migrate/fca0b4ac4518cc3c3cc78b4eadb583f3.png)
那么当这个对象没有被引用时会发生什么呢?我们知道Java中有自己的垃圾回收机制,许多初学者可能刚开始都会认为只要堆区中存在没有被引用到的对象就会被回收清理。
但真的是这样的吗,当这个对象没有被引用时,系统的回收机制难道就会立即回收清理又或是一定会去进行回收清理吗?
首先,立即回收肯定是不对的。当我们在java中new一个对象时,实际上这个对象可能会经历三个状态——可达状态
,可恢复状态
,不可达状态
。
可达状态
当一个对象被创建之后,如果有一个或多个变量去引用它时,那么此时这个对象就处于可达状态,也就是这个对象我们是可以触及到,可以通过引用变量来对其进行操作
可恢复状态
当一个对象不再被任何变量所引用时,此时它并不会马上被回收,而是会进入到可恢复的状态。这个状态下的对象,系统的回收机制将准备回收它所占用的内存。
在Java的Object类中提供了一个finalize()方法。在GC准备释放对象所占用的内存空间之前,它将首先调用finalize()方法来清理资源。
但如果在调用finalize方法时重新让该对象被一个引用变量所引用时,那么该对象又可以变回可达状态,正如其名——可恢复状态。像匿名对象它一开始就会进入可恢复状态,因为此时的它并没有被引用。
当然,如果没有变量去引用它的话,那么就将会进入不可达状态。
不可达状态
当对象进入可恢复状态后,并且调用finalize()方法后也并没有变量去引用它,那么此时这个对象就会进入不可达状态。当对象到达此状态时,系统才会真正回收它所占的资源。
![7fb43caec3a6534c730c604f62a6e86c.png](https://i-blog.csdnimg.cn/blog_migrate/3980932ded12097dcdbafea7b06e7583.png)
2. finalize机制
其实上面就是java对象在内存中会经历的状态,我们接下来就finalize再拓展一下
在Java中,由于GC的自动回收机制,我们并不能保证finalize方法会被及时地被调用,因为垃圾对象的回收时机具有不确定性,它对于我们来说完全是透明的。所以其实我们也不能保证它们会被执行,这就对应了上面第二个问题,程序可能由始至终都未触发垃圾回收,在退出程序后,这个对象也可能还是没有被回收。
而这也是finalize机制饱受诟病的原因,因为在回收对象前一定要执行finalize()方法,而且还不能保证及时执行,导致对象不能被及时回收,可能会出现在耗尽资源之前,gc仍未触发的这种情况。
所以从JDK9开始,finalize机制被弃用,采用了cleaner机制。
Cleaner机制不如Finalizer机制那样危险,但仍然是不可预测,运行缓慢并且通常是不必要的。关于cleaner机制我就不多讲了,感兴趣的话可以自己去了解。