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)
_
しかし、キューは空ではありません。アプリをしばらく使用した後でヒープをダンプすると、キューは文字通り何千ものエントリの長さになります。データ構造も壊れているようには見えません:
割り当ててガベージコレクションを行った後で再度ダンプすると、キューの先頭が以前と同じMatrixインスタンスであることがわかります。
ある時点でリリースする必要があるいくつかのC++オブジェクトを保持しているため、これに気づきました。ファイナライザーがJNI関数を呼び出して、C++側で愚かなことをすると、何らかの理由でそれが壊れる可能性があると思いますが、すべてのログは、すべてのファイナライザーが正常に実行され、ランダムに呼び出されなくなるまで何もスローせずに戻っていることを示しています。また、Watchdogは長時間実行されて例外をスローするファイナライザーを処理することになっているため、アプリ全体などをセグフォールトする以外に、ファイナライズ呼び出しでデーモンを壊すことは実際には不可能です。
明示的なSystem.runFinalization()
を試しましたが、実行されないデーモンを待って、メインスレッドを永久にハングさせるだけです。
これがどのように起こり得るかについて何か考えはありますか?
これは、finalizeメソッドで 復活 であるいくつかのオブジェクトに関係していると思います。
これから段落を引用します 質問 。
ファイナライザスレッドが実行されるため、ガベージコレクションが動作してオブジェクトに関連付けられたリソースがクリーンアップされます。私がそれを正確に見ている場合、ファイナライザーはこのオブジェクトへのロックを取得できません:Java.lang.ref.ReferenceQueue.remove(ReferenceQueue.Java:118)なぜならJavaオブジェクトはメソッドを実行しているため、ファイナライザスレッドは、そのオブジェクトが現在のタスクで終了するまでロックされます。
多分それはあなたが持っている状況です。