7

Ho passato quasi un giorno intero a cercare di scoprire il motivo di una perdita di memoria in Android. C'è un'attività che apro/chiudo molte volte (con un timer). Dopo un po 'mi stavo errori OutOfMemory:GC non dovrebbe essere eseguito automaticamente in Xamarin.Android prima di esaurire la memoria?

enter image description here

ho visto la memoria salendo costantemente in Xamarin Profiler ogni volta che l'attività ha aperto:

enter image description here

ho fatto che non ci fossero proprietà o gestori di eventi che potrebbero essere bloccati in quella attività. Ho persino rimosso ogni immagine, i pulsanti, ecc., Cercando di individuare ciò che stava causando la perdita di memoria. Ancora lo stesso ...

Poi ho fatto GC.Collect() nel metodo OnResume dell'attività principale (quello che apre l'attività problematica). Ora posso vedere la memoria andare su e giù come dovrebbe. È possibile vedere il risultato nello screenshot:

enter image description here

Secondo Xamarin docs:

Il GC verrà eseguito quando l'heap minore ha esaurito la memoria per nuove allocazioni

Ma questo non sta realmente accadendo

+3

lettura Rilevante: https://developer.xamarin.com/guides/android/advanced_topics/garbage_collection/#Cross-VM_Object_Collections e http://stackoverflow.com/questions/ 28863058/xamarin-android-finalizer-not-getting-called-when-leaving-the-activity-to-go-to/28868582 # 28868582 – matthewrdev

risposta

9

Si consiglia di leggere un po 'più in basso nel tuo link sotto Aiutare il GC: The GC has an incomplete view of the process and may not run when memory is low because the GC doesn't know that memory is low. e Managed Callable Wrappers do not add additional instance members

In sostanza, sembrerebbe BaseActivity è un Android Callable Wrapper (ACW) e il Mono GC non sa quanto è grande, in modo che non sa di invocare il netturbino. Da quanto ho capito, l'ACW è un modo per implementare interfacce Android.

La soluzione è, come hai scoperto, chiamare manualmente il garbage collector che è raccomandato nei documenti di Xamarin quando si usano ACW.

http://developer.xamarin.com/guides/android/advanced_topics/garbage_collection/

----

Dal momento che il messaggio originale di questa risposta, la documentazione Xamarin hanno migliorato nella loro spiegazione di questa situazione:

Un'istanza di un Java .Lang.Object type o derivato type è di almeno 20 byte di dimensione. Managed Callable Wrappers non aggiunge ulteriori membri dell'istanza , quindi quando hai un'istanza di Android.Graphics.Bitmap che fa riferimento a un blob di memoria da 10 MB, il GC di Xamarin.Android non saprà che - il GC vedrà un 20- oggetto byte e non sarà in grado di determinare che è collegato ad oggetti allocati al runtime di Android che mantengono vivo il 10 MB di memoria.

Questo indica che, indipendentemente dal fatto che gli oggetti sono impostati su null o non, si dovrebbe ancora manualmente chiamare il Xamarin GC se state allocazione/deallocazione Wrappers richiamabili che potenzialmente possono consumare una grande quantità di memoria.

Operando sotto ipotesi un Java Object è 20 byte, se uno dovesse allocare e nullare 100 oggetti che consumano 10 MB ciascuno, il GC Xamarin ritiene che siano in uso 4000 byte di memoria. In realtà, ~ 1 GB è in uso e il GC può o non può essere invocato.

-3

La chiamata della garbage collection non garantisce l'esecuzione della garbage collection o l'esecuzione di tutte le allocazioni di memoria. Molte volte si tratta di rimuovere un riferimento a un oggetto. Se un oggetto ha un riferimento ad esso, non sarà garbage collection. Ho dovuto imparare questo nel modo più duro. Fondamentalmente per risolvere questo problema in qualsiasi momento è possibile annullare la nullità di un oggetto in qualsiasi momento e impostarlo quando necessario. Esempio:

CustomObject cusObj = null; 
if (cusObj == null) 
{ 
    cusObj = new CustomObject(); 
} 

Semplicemente facendo in modo di azzerare l'oggetto rimuove il riferimento. Ma come indicato nella risposta sopra puoi anche raccogliere i rifiuti. Ricorda che il GC non raccoglierà i rifiuti con un riferimento. Date un'occhiata a:

Garbage collection and references C#

+0

Come puoi leggere nella domanda, non è un problema di riferimento perché mi sono assicurato di pulisci tutto – xleon

+0

Non è vero che la causa principale degli errori nello spazio dell'heap è riferita a oggetti che non consentono al garbage collector di eseguire lì il lavoro. – yams

+0

Eliminare gli oggetti per eliminare il riferimento avrebbe eliminato il problema in primo luogo. – yams