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++ 側で愚かなことをすると、何らかの形でそれが壊れる可能性があると思いますが、すべてのログは、すべてのファイナライザーが正常に実行され、ランダムに呼び出されなくなるまで何もスローせずに戻ることを示しています。また、ウォッチドッグは実行時間が長すぎて例外をスローするファイナライザーを処理することになっているため、ファイナライズ呼び出しでデーモンを壊すことは実際には不可能です。

明示的に試してみましたSystem.runFinalization()が、実行されないデーモンを待って、メインスレッドを永久にハングアップさせるだけです。

これがどのように起こるか考えていますか?

4

1 に答える 1

2

これは、一部のオブジェクトがファイナライズ メソッドで復活したことに関係していると思います。

この質問から段落を引用します。

ファイナライザ スレッドが実行されるため、ガベージ コレクションが動作して、オブジェクトに関連付けられたリソースがクリーンアップされます。私が正しく見ている場合、ファイナライザーはこのオブジェクトへのロックを取得できません: java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:118) Javaオブジェクトがメソッドを実行しているため、ファイナライザースレッドはそのオブジェクトが現在のタスクを完了するまでロックされます。

多分それはあなたが持っている状況です。

于 2016-07-21T10:38:05.590 に答える