2016-05-03 24 views
17

Sto riscontrando un problema davvero strano in un'app Android. Dopo un certo punto (attorno all'avvio dell'attività principale e alla visualizzazione di un frammento) FinalizerDaemon interrompe l'elaborazione degli oggetti e la raccolta continua a accumularsi. Guardando una discarica filo, sembra essere bloccato su ReferenceQueue.remove():Android FinalizerDaemon riagganciare

"[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) 

Eppure la coda non è vuota. Se eseguo il dump dell'heap dopo aver usato l'app per un po ', la coda è letteralmente composta da migliaia di voci. Anche la struttura dati non sembra danneggiata: FinalizerDaemon instance showing a non-empty ReferenceQueue

Il dumping di nuovo dopo l'allocazione e la raccolta di dati obsoleti mostra che il capo della coda è la stessa istanza di Matrix di prima.

Ora, ho notato questo perché sto mantenendo alcuni oggetti C++, che devono essere rilasciati ad un certo punto. Mentre sospetto che un finalizzatore che richiama JNI funzioni e che faccia qualcosa di stupido sul lato C++ possa in qualche modo romperlo, tutti i miei log indicano che tutti i finalizzatori stanno funzionando bene e ritornano senza lanciare nulla finché non si fermano casualmente. Inoltre, non dovrebbe essere veramente possibile per una chiamata finalizzata per rompere il Daemon, a meno di segmentare l'intera app o qualcosa del genere, dal momento che il Watchdog dovrebbe gestire i finalizzatori che girano troppo a lungo e generano un'eccezione.

Ho provato un System.runFinalization() esplicito e tutto ciò che fa è appendere il thread principale per sempre, in attesa del demone che non funziona mai.

Qualche idea su come questo potrebbe accadere?

+0

Guardando https://android.googlesource.com/platform/libcore/+/marshmallow-mr1-release/luni/src/main/java/java/lang/ref/ReferenceQueue.java, è in attesa per sempre di qualcosa rimuovere. Supponendo che sia bloccato qui (rispetto all'esecuzione molto veloce e ti capita di capirlo qui), ciò suggerirebbe che non vengano aggiunti nuovi riferimenti. Se vedi 'head! = Null' su quella coda, sembrerebbe che qualsiasi cosa stia facendo il GC per aggiungere riferimenti non riesce a segnalare la coda. Quale versione di Android? – fadden

+0

@fadden Ho modificato la domanda. L'esecuzione di dump di heap ripetuti mostra che il capo della coda non è nullo e non si sposta dallo stesso oggetto. Nessuno dei miei registri nei finalizzatori viene stampato dopo il punto in cui sembra rimanere bloccato. Sarebbe alquanto improbabile che io lo catturi casualmente ogni volta che cerco, in diverse parti dell'app e su diversi dispositivi. L'ho riprodotto su un Nexus 4 (5.1) e un emulatore x86 6.0, e ho motivo di sospettare che ciò avvenga su una dozzina di altri dispositivi di test che non ho ancora avuto modo di connettermi al mio Studio Android. – IvoDankolov

+0

Sembra certamente che ReferenceQueue non si comporti correttamente. O si tratta di un problema diffuso che nessuno ha notato (improbabile), o che la tua app ha inavvertitamente fatto impazzire. Forse qualche codice nativo ha scritto al di fuori dei confini dell'oggetto e ha cestinato un blocco monitor, quindi 'notify()' non funziona più? Si potrebbe provare ad allegare un debugger e ad avanzare o cancellare manualmente 'head' per vedere se inizia a funzionare quando si rilascia la voce corrente (e quindi creare un po 'di spazzatura per far sì che la coda segnali). – fadden

risposta

1

Credo che questo abbia a che fare con alcuni oggetti che sono resurrected nei loro metodi di finalizzazione.

Cito un paragrafo da questo question.

Il thread di finalizzazione viene eseguito in modo che la garbage collection funzioni per pulire le risorse risorse associate a un oggetto. Se sto vedendo corectly, il finalizzatore non può ottenere il blocco per questo oggetto: java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:118) perché l'oggetto Java è in esecuzione un metodo, quindi il thread del finalizzatore è bloccato finché l'oggetto non ha finito con il compito corrente.

Forse è la situazione che hai.

+0

temo che non sia così. Quello che dice Threaddump è solo che FinalizerDaemon è in attesa per sempre che un oggetto diventi disponibile su ReferenceQueue. Ma perché non ci sono oggetti in arrivo? –

+0

Se hai ragione e sto trascurando qualcosa: puoi dire esattamente quale oggetto java sta eseguendo un metodo che blocca il finalizzatore? –

+0

Ecco un Threadump: https://code.google.com/p/android/issues/attachmentText?id=215906&aid=2159060001000&name=threads_report.txt&token=ABZ6GAf2Zh1q6ogUdf33PqBXMILxOHjAjA%3A1469110397989 –

Problemi correlati