У меня очень странная проблема в приложении для 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)
Но очередь не пуста. Если я сбрасываю кучу после использования приложения некоторое время, очередь составляет буквально тысячи записей. Структура данных также не выглядит разбитой:
Сброс снова после выделения и сбора мусора еще несколько показывает, что глава очереди является тем же экземпляром матрицы, что и раньше.
Теперь я заметил это, потому что я сохраняю некоторые объекты на C++, которые должны быть выпущены в какой-то момент. Хотя я подозреваю, что финализатор, вызывающий функции JNI и делающий что-то глупое на стороне C++, может как-то сломать его, все мои журналы показывают, что все финализаторы работают нормально и возвращаются, не бросая ничего, пока они просто случайно не перестанут получать вызов. Кроме того, не должно быть возможным, чтобы окончательный вызов нарушил Демон, не выполнив segfaulting всего приложения или что-то еще, поскольку Watchdog должен обрабатывать финализаторы, которые работают слишком долго и генерируют исключение.
Я пробовал явное System.runFinalization()
, и все, что он делает, вечно вешает основную нить, ожидая, что демон никогда не запускается.
Любая идея, как это может произойти?
Глядя на https://android.googlesource.com/platform/libcore/+/marshmallow-mr1-release/luni/src/main/java/java/lang/ref/ReferenceQueue.java, он всегда ждет чего-то удалять. Предполагая, что он застрял здесь (и работает очень быстро, и вы просто поймаете его здесь), это предполагает, что новые ссылки не добавляются. Если вы видите в этой очереди 'head! = Null', тогда будет казаться, что все, что делает GC для добавления ссылок, не сигнализирует очередь. Какая версия Android? – fadden
@fadden Я редактировал вопрос. При повторном сбросе кучи показывает, что голова очереди не равна нулю и не перемещается от одного и того же объекта. Ни один из моих журналов в финализаторах не печатает ни после того момента, когда кажется, что он застрял. Было бы маловероятно, что я просто случайно поймаю его в ожидании каждый раз, когда я пытаюсь, в разных частях приложения и на разных устройствах. Я воспроизвел его на эмуляторе Nexus 4 (5.1) и x86 6.0, и у меня есть основания подозревать, что это происходит на десятке других тестовых устройств, которые я еще не подключил к подключению к моей Android-студии. – IvoDankolov
Это, безусловно, звучит так, как ReferenceQueue не ведет себя правильно. Либо это широко распространенная проблема, которую никто не заметил (маловероятно), или ваше приложение случайно пошатнулось. Может быть, какой-то собственный код написал вне границ объекта и уничтожил блокировку монитора, поэтому 'notify()' больше не работает? Вы можете попробовать установить отладчик и вручную продвигать или очищать 'head', чтобы узнать, начинает ли он работать, когда вы отбрасываете текущую запись (а затем создаете еще больше мусора, чтобы заставить очередь сигнализировать). – fadden