2016-05-03 2 views
17

У меня очень странная проблема в приложении для Android. После определенного момента (вокруг, когда начинается основная активность и отображается фрагмент) FinalizerDaemon просто прекращает обработку объектов, а мусор продолжает накапливаться. Глядя на нить свалку, это, кажется, застрял на ReferenceQueue.remove():Android FinalizerDaemon подвешивает

"[email protected]" 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) 

Но очередь не пуста. Если я сбрасываю кучу после использования приложения некоторое время, очередь составляет буквально тысячи записей. Структура данных также не выглядит разбитой: FinalizerDaemon instance showing a non-empty ReferenceQueue

Сброс снова после выделения и сбора мусора еще несколько показывает, что глава очереди является тем же экземпляром матрицы, что и раньше.

Теперь я заметил это, потому что я сохраняю некоторые объекты на C++, которые должны быть выпущены в какой-то момент. Хотя я подозреваю, что финализатор, вызывающий функции JNI и делающий что-то глупое на стороне C++, может как-то сломать его, все мои журналы показывают, что все финализаторы работают нормально и возвращаются, не бросая ничего, пока они просто случайно не перестанут получать вызов. Кроме того, не должно быть возможным, чтобы окончательный вызов нарушил Демон, не выполнив segfaulting всего приложения или что-то еще, поскольку Watchdog должен обрабатывать финализаторы, которые работают слишком долго и генерируют исключение.

Я пробовал явное System.runFinalization(), и все, что он делает, вечно вешает основную нить, ожидая, что демон никогда не запускается.

Любая идея, как это может произойти?

+0

Глядя на https://android.googlesource.com/platform/libcore/+/marshmallow-mr1-release/luni/src/main/java/java/lang/ref/ReferenceQueue.java, он всегда ждет чего-то удалять. Предполагая, что он застрял здесь (и работает очень быстро, и вы просто поймаете его здесь), это предполагает, что новые ссылки не добавляются. Если вы видите в этой очереди 'head! = Null', тогда будет казаться, что все, что делает GC для добавления ссылок, не сигнализирует очередь. Какая версия Android? – fadden

+0

@fadden Я редактировал вопрос. При повторном сбросе кучи показывает, что голова очереди не равна нулю и не перемещается от одного и того же объекта. Ни один из моих журналов в финализаторах не печатает ни после того момента, когда кажется, что он застрял. Было бы маловероятно, что я просто случайно поймаю его в ожидании каждый раз, когда я пытаюсь, в разных частях приложения и на разных устройствах. Я воспроизвел его на эмуляторе Nexus 4 (5.1) и x86 6.0, и у меня есть основания подозревать, что это происходит на десятке других тестовых устройств, которые я еще не подключил к подключению к моей Android-студии. – IvoDankolov

+0

Это, безусловно, звучит так, как ReferenceQueue не ведет себя правильно. Либо это широко распространенная проблема, которую никто не заметил (маловероятно), или ваше приложение случайно пошатнулось. Может быть, какой-то собственный код написал вне границ объекта и уничтожил блокировку монитора, поэтому 'notify()' больше не работает? Вы можете попробовать установить отладчик и вручную продвигать или очищать 'head', чтобы узнать, начинает ли он работать, когда вы отбрасываете текущую запись (а затем создаете еще больше мусора, чтобы заставить очередь сигнализировать). – fadden

ответ

1

Я считаю, что это связано с некоторыми объектами resurrected в их методах завершения.

Я приведу параграф из этого question.

Запуск финализатора работает, поэтому сбор мусора работает, чтобы очистить ресурсы, связанные с объектом. Если я вижу это по-другому, финализатор не может получить блокировку этого объекта: java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:118), потому что java-объект выполняет метод, поэтому поток финализатора заблокирован , пока этот объект не завершит свою текущую задачу.

Возможно, это ваша ситуация.

+0

Боюсь, что это не так. То, что говорит Threaddump, - это просто FinalizerDaemon, который ждет навсегда, чтобы объект стал доступен в ReferenceQueue. Но почему нет объектов? –

+0

Если вы правы, и я что-то пропускаю: вы можете точно указать, в каком java-объекте работает метод, который блокирует финализатор? –

+0

Вот пример: https://code.google.com/p/android/issues/attachmentText?id=215906&aid=2159060001000&name=threads_report.txt&token=ABZ6GAf2Zh1q6ogUdf33PqBXMILxOHjAjA%3A1469110397989 –

Смежные вопросы