上一篇:008-JVM - 清除阶段算法之三:标记 - 压缩算法 Mark-Compacthttps://blog.csdn.net/fsjwin/article/details/111342195 标记为不可达的...... 上一篇:008-JVM - 清除阶段算法之三:标记 - 压缩算法 Mark-Compact juejin.cn/post/690901…
标记为不可达的对象一定会被回收吗? 这是一个好问题,一般这么问的答案肯定是否定的!!! Object.java 中的方法:
protected void finalize() throws Throwable { } finalization 机制简单说就是免死金牌,或者在沙头前的一道圣旨。
Java 语言提供了对象终止 (finalization) 机制来允许开发人员提供对象被销毁之前的自定义处理逻辑。
当垃圾回收器发现没有引用指向一个对象, 即: 垃圾回收此对象之前, 总会先调用这个对象的 finalize() 方法。
finalize() 方法允许在子类中被重写, 用于在对象被回收时进行资源释放(当然也可以随便做些事情如,不让他回收,让他重新复活)。通常在这个方法中进行一些资源释放和清理的工作, 比如关闭文件、套接字和数据库连接等。
永远不要主动调用某个对象的 finalize() 方法, 应该交给垃圾回收机制调用。理由包括下面三点:
在 finalize() 时可能会导致对象复活。
finalize() 方法的执行时间是没有保障的, 它完全由 GC 线程决定, 极端情况下,若不发生 GC , 则finalize() 方法将永远没有执行机会。
一个糟糕的 finalize() 会严重影响GC 的性能。
如果从所有的根节点都无法访问到某个对象, 说明对象己经不再使用了。一般来说,此对象需要被回收。但事实上, 也并非是 “非死不可” 的, 这时候它们暂时处于 “ 缓刑” 阶段。一个无法触及的对象有可能在某一个条件下 “ 复活” 自己, 如果这样, 那么对它的回收就是不合理的, 为此, 定义虚拟机中的对象可能的三种状态。如下**:**
可触及的: 从根节点(GCRoot)开始, 可以到达这个对象。
可复活的: 对象的所有引用都被释放, 但是对象有可能在 中复活。
不可触及的: 对象的 finalize() 被调用, 并且没有复活, 那么就会进入不可触及状态。不可触及的对象不可能被复活, 因为 finalize() 只会被调用一次。
以上 3 种状态中, 是由于 finalize() 方法的存在, 进行的区分。只有在对象不可触及时才可以被回收。
有一个优先级比较低的线程,专门调用 finalize() 方法
判定一个对象。obj 是否可回收, 至少要经历两次标记过程:
如果对象 obj 到 GC Roots 没有引用链, 则进行第一次标记。
进行筛选, 判断此对象是否有必要执行 finalize() 方法。
(1) 如果对象 obj 没有重写 finalize() 方法, 或 finalize() 方法己经被虚拟机调用过,则虚拟机视为 “ 没有必要执行” 。obj 被判定为不可触及的。
(2) 如果对象 obj 重写了 finalize() 方法, 且还未执行过, 那么 obj 会被插入到F-Queue队列中, 由一个虚拟机自动创建的、低优先级的 finalizer 线程触发其 finalize() 方法执行。
(3) finalize() 方法是对象逃脱死亡的最后机会, 稍后 GC 会对 F-Queue 队列中的对象进行第二次标记: 如果 obj 在 finalize() 方法中与引用链上的任何一个对象建立了联系,那么在第二次标记时,obj 会被移出 “ 即将回收 F-Queue” 集合。
之后, 对象会再次出现没有引用存在的情况。在这个情况下 finalize() 方法不会被再次调用, 对象会直接变成不可触及的状态, 也就是说, 一个对象的 finalize() 方法只会被调用一次。
关键点:finalize() 方法中和 gc roots 中的对象发生关系,就可免一死!