2015-05-22 20 views
10

Mi sono imbattuto in una libreria per il rilevamento delle perdite di memoria in Android (Java) chiamato LeakCanary ma non riesco a capire l'esempio in cui perdono la memoria. Qualcuno potrebbe spiegare come e perché il codice mostrato nel loro esempio è una perdita di memoria.Perché si tratta di una perdita di memoria

class Cat { 
} 
class Box { 
    Cat hiddenCat; 
} 
class Docker { 
    static Box container; 
} 

// ... 

Box box = new Box(); 
Cat schrodingerCat = new Cat(); 
box.hiddenCat = schrodingerCat; 
Docker.container = box; 

e poi guardano la variabile schrodingerCat di perdite che dà una perdita mostrato nel seguente modo (che non so come relazionarsi con il codice di cui sopra).

Qualsiasi aiuto con la spiegazione della perdita e il modo in cui il rilevamento si riferisce ad esso sarebbe molto utile. Inoltre, alcuni buoni articoli per i principianti sarebbero buoni.

Grazie!

risposta

13

In primo luogo, cerchiamo di capire che cosa è un perdita di memoria :

Definizione

Perdita di memoria è di dati allocato (bitmap, oggetti, array, ecc) nella RAM che il garbage collector (GC) non è in grado di liberare, anche se non è più necessario dal programma.

Esempio

Un utente sta aprendo una vista che mostra un'immagine. Carichiamo la bitmap nella memoria. Ora l'utente esce dalla vista e l'immagine non è più necessaria e non vi è alcun riferimento ad essa dal codice. In quel momento il GC entra in azione e lo rimuove dalla memoria. MA, se avessimo ancora un riferimento ad esso, il GC non saprà che è OK per la rimozione e sarebbe rimasto nella RAM prendendo spazio non necessario - alias Perdita di memoria.

Cat in a Box

Diciamo che abbiamo un oggetto Cat nella nostra app, e noi tenerlo in un oggetto Box. Se teniamo la scatola (abbiamo un riferimento all'oggetto Box) e la casella contiene Cat, il GC non sarà in grado di pulire l'oggetto Cat dalla memoria.

La finestra mobile è una classe che ha un riferimento statico alla nostra casella. Ciò significa che, a meno che non lo annulli, o riassegniamo il valore, il Docker continuerà a fare riferimento alla Scatola. Prevenire che la scatola (e il gatto interno) non vengano mai rimossi dalla memoria dal GC.

Quindi, abbiamo bisogno del Gatto? è ancora rilevante per l'app?

Spetta allo sviluppatore decidere per quanto tempo è necessario il gatto. LeakCanary e altri strumenti diagnostici suggeriscono una possibile perdita di memoria. PENSANO che l'oggetto (Cat) potrebbe non essere più necessario quindi avvisano che si tratta di una perdita.

Recap

Nell'esempio, danno uno scenario comune di una perdita di memoria. Quando si utilizza un riferimento statico statico, si impedisce al GC di pulire un oggetto. Si consiglia di leggere questo:

* GC ROOT static Docker.container 
* references Box.hiddenCat 
* leaks Cat instance 

come:

  • Cat oggetto forza non essere più utilizzato, ma non è stato rimosso dalla memoria del GC.
  • Il motivo per cui l'oggetto Cat non è stato rimosso poiché Box ha un riferimento.
  • Il motivo per cui la casella dell'oggetto non è stata rimossa poiché la finestra mobile ha un riferimento statico.
  • Il riferimento statico tramite Docker è il ROOT dell'albero che causa la possibile perdita.
+1

Questa grande spiegazione dovrebbe essere aggiunta al wiki di LeakCanary :) – tieorange

1

Sembra che l'istanza RefWatcher usato per "assistere la variabile schrodingerCat di perdite":

refWatcher.watch(schrodingerCat); 

costringe una serie di GC passa e se il riferimento passato in non viene raccolto durante quelle GC passa è considerato una perdita.

Dal momento che la statica Docker.container.hiddenCat è mantenere un GC radicata riferimento all'oggetto originariamente conosciuto come schrodingerCat, non può essere GC'ed in modo che quando si chiede RefWatcher a controllare. Pertanto ti consente di sapere che l'oggetto non può essere raccolto.

+1

eh? Potresti dumbelo per favore ancora un po ':) – Bootstrapper

+0

'Docker.container.hiddenCat' è un riferimento statico all'oggetto creato come' schrodingerCat'. Quindi quell'oggetto non può essere garbage collection nel momento in cui 'RefWatcher' è attivato per quell'oggetto. –

1

vi consiglio di leggere questa risposta https://stackoverflow.com/a/11908685/1065810

Sarà probabilmente aiuterà a capire l'esempio precedente.

In breve, nel vostro esempio, la classe Docker mantiene un riferimento a una casella. Anche quando la casella contenitore non è più necessaria, la classe Docker contiene ancora un riferimento ad essa creando così una perdita di memoria.

Fammi sapere se questo aiuta.

Problemi correlati