2012-06-21 11 views
7

Sto lavorando su un'applicazione .NET in cui sembra che ci sia una perdita di memoria. So che il libro di testo risponde, che gli eventi devono essere annullati, gli oggetti usa e getta dovrebbero essere smaltiti ecc ...Debugging perdite di memoria .NET - come sapere cosa contiene un riferimento a cosa?

Ho un cablaggio di prova in grado di riprodurre l'errore. Nel finalizzatore di una certa classe scrivo per consolare

public class Foo 
{ 
    // Ctor 
    public Foo() 
    { 
    } 

    ~public Foo() 
    { 
     Console.WriteLine("Foo Finalized"); 
    } 
} 

Nel test harness, sto creando una singola istanza di Foo (che a sua volta crea e interagisce con centinaia di altri tipi) quindi rimuoverlo e invocando la Netturbino.

Sto riscontrando che Foo Finalizer non viene mai chiamato. Ho una classe simile con questa configurazione che è finalizzata come test di controllo.

Quindi la mia domanda è questa:

Come è possibile determinare con strumenti di origine commerciale o aprire esattamente quello sta tenendo un riferimento alla Foo?

Ho una licenza professionale per dotTrace Memory profiler ma non riesco a capire dai file della guida come usarlo.

Aggiornamento: Ora sto usando dotMemory 4.0, che è il successore del (buono, ma inutilizzabile) dotTrace Memory 3.5.

+1

se hai già un profiler impara ad usarlo - non ho lavorato molto con dotTrace ma io gli altri due sono simili nei loro modelli d'uso e ho bisogno di un po 'di "entrare" anche in questo – Carsten

+0

@ CarstenKönig +1, Sto scavando in dotTrace ora. Capisco che posso trovare una lista di oggetti non raccolti per namespace (così ho trovato il mio Foo ingiurioso) e cosa contiene un riferimento a loro, di nuovo filtrato per namespace (centinaia di), ora esaminando un elenco di gestori di eventi sospetti ecc ... –

+0

@ CarstenKönig, infatti, l'ha trovato usando dotTrace! Ha la funzione di approfondire il grafico da gcroot -> Foo, solo un po 'difficile da trovare. Saluti :) –

risposta

3

Il finalizzatore non è chiamato deterministicamente, quindi attenzione di usarlo per tracciare le cose in modo affidabile. Se si rimuove il finalizzatore e si utilizza invece un WeakReference<Foo>, si dovrebbe essere in grado di determinare se l'oggetto è stato raccolto.

Tutti i profiler di memoria dovrebbero essere in grado di trovare un problema come questo, ma con un diverso grado di difficoltà. Personalmente ho usato ANTS che è molto facile da usare, ma non libero. Ti aiuterà a mostrare un diagramma di riferimento all'istanza di Foo, a partire da un oggetto radice GC. Vedendo questo diagramma è solitamente facile individuare chi detiene il riferimento.

2

È possibile utilizzare profiler di memoria per identificare le perdite di memoria. Qui ci sono alcuni,

MemProfiler

ANTS Profiler

+0

Votato per ANTS Profiler. In un'applicazione aziendale ragionevolmente grande, è riuscito a trovare un'enorme perdita di risorse che era sfuggita al rilevamento per 3 anni. – Contango

6

Avere uno look nell'estensione SOS debugger (È gratuito, può essere utilizzato all'interno di Visual Studio).

È possibile trovare this e this utili per iniziare.

Se è stato impostato succefully SOS (questo può essere difficile a volte), sapendo ciò che contiene un riferimento a ciò che è facile come

// load sos 
.load sos 
// list of all instances of YourTypeName in memory with their method tables 
!DumpHeap -type YourTypeName 
// put here the method table displayed by the previous command 
// it will show you the memory address of the object 
!DumpHeap -mt 07f66b44    
// displays information about references the object at the specified address 
!GCRoot 02d6ec94 
+0

Grazie per questo, ci proverò sicuramente. Sarebbe bello se ci fosse un buon tutorial su dotTrace ma purtroppo no! –

1

In primo luogo non si dovrebbe usare un finalizzatore, perché:

operazioni Finalizzare presentano le seguenti limitazioni:

  • il tempo esatto in cui il finalizzatore viene eseguita durante immondizia collezione non è definita. Non è garantito che le risorse vengano rilasciate in qualsiasi momento specifico di , a meno che non si chiami un metodo Close o un metodo Dispose.

  • Non è possibile eseguire i finalizzatori di due oggetti in qualsiasi ordine specifico , anche se un oggetto fa riferimento all'altro. Cioè, se l'oggetto ha un riferimento all'oggetto B ed entrambi hanno i finalizzatori, l'oggetto B potrebbe essere già finalizzato all'avvio del finalizzatore dell'oggetto A.

  • Il thread su cui viene eseguito il finalizzatore non è specificato.

Citato da: http://msdn.microsoft.com/en-us/library/system.object.finalize.aspx
Io suggerirei di usare metodo Dispose, invece.

In secondo luogo, qualsiasi profiler di memoria dovrebbe essere in grado di trovare ciò che contiene tali riferimenti. Personalmente stavo usando ANTS Profiler, è uno strumento molto carino e ha una documentazione abbastanza ricca. Puoi provare a leggere questo documento: http://downloads.red-gate.com/HelpPDF/ANTS_Memory_Profiler/InstanceCategorizer.pdf Il classificatore di istanze visualizza catene di riferimenti da serie di oggetti a radice GC.

+0

Mentre hai perfettamente ragione, in alcuni casi è davvero necessario utilizzare Finalizer. Considera che hai creato un controllo personalizzato per il rendering di superfici 3D che puoi ridistribuire agli utenti finali. È molto improbabile che gli utenti finali chiamino .Dispose() sul controllo una volta che non è più in uso. Si aspettano che "funzioni solo". Anche WPF garbage raccoglie le visualizzazioni a volte quando sono basate su modelli e in un controllo di tabulazione e con tab e out. In questi casi è impossibile chiamare .Dispose e Finalizer è l'opzione migliore per rilasciare risorse non gestite chiamando direttamente Dispose per te, se Non ancora –

6

Il debug delle perdite di memoria può essere un processo abbastanza complicato e richiede una conoscenza approfondita della logica del programma e almeno di alcuni interni .Net (in particolare il comportamento del garbage collector).

Per ulteriori informazioni consultare i seguenti link:

buona introduzione

Hands-on corso:

GC e.interni netti

WinDbg con estensione SOS

Good Luck!

Problemi correlati