19

我在 Android 应用程序中遇到了一个非常奇怪的问题。在某个点之后(大约在主要活动开始并显示片段时),FinalizerDaemon 停止处理对象并且垃圾不断堆积。查看线程转储,它似乎卡在ReferenceQueue.remove()

"FinalizerDaemon@4461" daemon prio=5 waiting
  java.lang.Thread.State: WAITING
      at java.lang.Object.wait(Object.java:-1)
      at java.lang.Object.wait(Object.java:423)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:101)
      - locked <0x1173> (a java.lang.ref.ReferenceQueue)
      at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:72)
      at java.lang.Daemons$FinalizerDaemon.run(Daemons.java:185)
      at java.lang.Thread.run(Thread.java:818)

然而队列不是空的。如果我在使用应用程序一段时间后转储堆,则队列实际上有数千个条目。数据结构看起来也没有损坏: 显示非空 ReferenceQueue 的 FinalizerDaemon 实例

在分配和垃圾收集更多之后再次转储表明队列的头部与之前的 Matrix 实例相同。

现在,我注意到了这一点,因为我保留了一些需要在某个时候释放的 C++ 对象。虽然我怀疑终结器调用 JNI 函数并在 C++ 端做一些愚蠢的事情可能会以某种方式破坏它,但我所有的日志都表明所有终结器都运行良好并且没有抛出任何东西就返回,直到它们随机停止被调用。此外,finalize 调用实际上不可能破坏守护程序,除非对整个应用程序进行段错误或其他内容,因为 Watchdog 应该处理运行时间过长并引发异常的终结器。

我尝试了一个显式的System.runFinalization()方法,它所做的只是永远挂起主线程,等待永远不会运行的守护进程。

知道这怎么会发生吗?

4

1 回答 1

2

我相信这与某些对象在它们的 finalize 方法中复活有关。

我将从这个问题中引用一段话。

终结器线程运行,因此垃圾收集操作以清理与对象关联的资源。如果我正确地看到它,终结器无法锁定该对象: java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) 因为 java 对象正在运行一个方法,所以终结器线程是锁定,直到该对象完成其当前任务。

也许这就是你的情况。

于 2016-07-21T10:38:05.590 回答