java - 在 Java 中如何将对象标记为已完成(以便不会第二次调用 finalize 方法)?

标签 java garbage-collection finalizer finalize finalization

主要问题在主题中,但让我展示一下我对 Java 终结过程的看法,以便我可以问你更多。

好吧,gc 通过标记所有 Activity 对象来开始垃圾收集。当所有可达对象都标记为“Activity ”时。所有其他对象都不可访问。下一步是检查每个无法到达的对象,并确定是可以立即清除还是应该首先确定。 如果对象的 finalize 方法有主体,那么 gc 会考虑下一个方法,那么这个对象是可终结的,应该被终结;如果对象的 finalize 方法有一个空主体(protected void finalize(){ }),那么它是不可终结的,可以立即被 gc 清除。(我说得对吗?)
所有可终结的对象将被放入同一个队列中,以便稍后被一个一个地终结。据我所知,一个可终结的对象在等待轮到它被终结时会花费大量时间被放入队列。发生这种情况是因为通常只有一个名为 Finalizer 的线程从队列中取出对象并调用它们的 finalize 方法,当我们在某个对象的 finalize 方法中进行一些耗时操作时,队列中的其他对象将等待很长时间才能完成。那么当一个对象已经完成时,它被标记为 FINALIZED 并从队列中删除。 在下一个垃圾收集过程中,收集器将(再次)看到此对象无法访问并且具有非空的 finalize 方法(再次),因此应将此对象(再次)放入队列中 - 但它赢了不是因为收集器以某种方式看到这个对象被标记为 FINALIZED。(这是我的主要问题:这个对象以什么方式被标记为 FINALIZED,收集器如何知道这个对象不应该又要定案了?)

最佳答案

只要我们在谈论 HotSpot JVM ...

对象本身未标记为已完成。

每次创建新的 finalize 对象时,JVM 都会创建一个额外的对象 FinalizerRef(这有点类似于 Weak/Soft/Phantom 引用)。

一旦您的对象被证明无法通过强引用访问,就会处理对该对象的特殊引用。您对象的 FinalizerRef 将被添加到终结器队列(这是链表,与其他引用类型相同)。

当终结器线程使用队列中的 FinalizerRef 时,它会将其指向对象的空指针置空(尽管线程将保持对对象的强引用,直到终结器完成)。

一旦 FinalizerRef 无效,对象将无法再进入终结器队列。

顺便说一句

您可以使用 -XX:+PrintReferenceGC ( see more GC diagnostic JVM options ) 在 GC 日志中查看偏好处理时间(和引用数)

关于java - 在 Java 中如何将对象标记为已完成(以便不会第二次调用 finalize 方法)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21809922/

相关文章:

java - 有效的 Java - 永远不要依赖终结器来更新关键的持久状态

java - 为什么 == 对于 Integer.valueOf(500) 返回 false 但对于 5 返回 true?

java - 如何让我的应用程序图标在 Mac Dock 中弹起

java - ViewPager.setAdapter 需要 200 毫秒到 300 毫秒才能执行

python - 为什么要重新初始化多进程工作人员?

c# - 在终结器线程中诊断 NullReferenceException

.net - 如何识别GC Finalizer线程?

java - 最好的方法是将jsvc与您的java服务打包为源代码,然后让使用它的人在使用前进行编译?

java - 在java中将大文件的数据缓存在内存中

java - 为什么 JFrame 对象似乎保持 Activity 状态,即使没有对它的引用?