2009-09-24 9 views
15

Ho un oggetto, che vive per sempre. Sto cancellando tutti i riferimenti che riesco a vedere, dopo averlo usato, ma non è ancora stato raccolto. Il suo ciclo di vita è piuttosto sofisticato, quindi non posso essere sicuro che tutti i riferimenti siano stati cancellati.Trova riferimenti all'oggetto in runtime

if (container.Controls.Count > 0) 
{ 
    var controls = new Control[ container.Controls.Count ]; 
    container.Controls.CopyTo(controls, 0); 

    foreach (var control in controls) 
    { 
     container.Controls.Remove(control); 
     control.Dispose(); 
    } 

    controls = null; 
} 

GC.Collect(); 
GC.Collect(1); 
GC.Collect(2); 
GC.Collect(3); 

Come posso scoprire che cosa riferimenti ce l'ha ancora? Perché non viene raccolto?

+0

Mostraci il tuo codice e potremmo essere in grado di aiutarti. Ricorda che la garbage collection non avviene necessariamente immediatamente. – Lazarus

+0

E immagino che la vera domanda sia, perché ti preoccupi di questo? Se si utilizzano risorse usa e getta, eliminarle quando non le si utilizza più, pulire le risorse di sistema non gestite e fare attenzione con l'internamento delle stringhe. –

+0

Il codice è: se (container.Controls.Count> 0) { \t \t \t \t controlli var = new Control [container.Controls.Count]; \t \t \t \t container.Controls.CopyTo (controlli, 0); \t \t \t \t foreach (var controllo nei controlli) { \t \t \t \t \t container.Controls.Remove (controllo); \t \t \t \t \t control.Dispose(); \t \t \t \t \t \t \t \t \t} \t \t \t \t controlli = null; \t \t \t} GC.Collect(); GC.Collect (1); GC.Collect (2); GC.Collect (3); Ma è ancora in memoria. Così meens, che l'acciaio ha radici. Come posso trovare queste radici? –

risposta

11

Provare a utilizzare un profiler di memoria , (ad esempio ants) che vi dirà cosa mantiene l'oggetto in vita. Cercando di indovinare questo tipo di problema è molto difficile.

Red-gate fornisce una prova di 14 giorni che dovrebbe essere più che sufficiente per risolvere questo problema e decidere se un profiler di memoria fornisce un valore a lungo termine.

ci sono un sacco di altri profiler di memoria presenti sul mercato (ad esempio .NET Memory Profiler) la maggior parte di loro hanno le prove libere, ma ho trovato che gli strumenti Red-Gate sono facili da usare, in modo da tendono provarli prima.

+0

Grazie, ci proverò! –

+0

Hanno anche alcuni video di formazione gratuiti (e documenti) ecc. Che spiegano come funziona il garbage collector .net che potresti trovare utile. –

+0

@ er-v: il tuo oggetto potrebbe essere stato raccolto ma la memoria potrebbe non essere stata recuperata da Windows. Il framework non deve restituire memoria al sistema operativo. – user7116

0

Non viene raccolto perché non sono stati rimossi tutti i riferimenti. Il GC contrassegnerà gli oggetti per la raccolta solo se non hanno radici nell'applicazione.

quali mezzi stai usando a check-up sul GC per vedere se ha raccolto l'oggetto?

2

Il garbage collection in .NET non è un sistema di conteggio delle (come COM), ma un'implementazione mark-and-sweep. Fondamentalmente, il GC funziona in momenti "casuali" quando sente la necessità di farlo, e la raccolta degli oggetti non è quindi deterministica.

È possibile, tuttavia, attivare manualmente una raccolta (GC.Collect()), ma potrebbe essere necessario attendere l'esecuzione dei finalizzatori (GC.WaitForPendingFinalizers()). In questo caso, tuttavia, è scoraggiante farlo perché potrebbe influire sull'efficienza della gestione della memoria (GC viene eseguito troppo spesso o attende l'esecuzione dei finalizzatori). Se l'oggetto esiste ancora, in realtà ha ancora qualche riferimento dal vivo da qualche parte.

3

Dovrete usare Windbg e Sosex estensione.

I !DumpHeap e !GCRoot comandi possono aiutare a identificare l'istanza, e tutti i restanti riferimenti che mantengono in vita.

3

Ho utilizzato .NET Memory Profiler per eseguire una seria profilazione della memoria su uno dei nostri progetti. È un ottimo strumento per esaminare la gestione della memoria della tua app. Non vengo pagato per queste informazioni :) ma mi ha aiutato molto.

+0

D'accordo, è uno strumento molto utile, specialmente quello visivo. –

3

Ho risolto un problema simile con l'estensione SOS (che a quanto pare non funziona più con Visual Studio 2013, ma funziona bene con le versioni precedenti di Visual Studio).

ho usato seguente codice per ottenere l'indirizzo dell'oggetto per il quale ho voluto tracciare riferimenti:

public static string GetAddress(object o) 
{ 
    if (o == null) 
    { 
     return "00000000"; 
    } 
    else 
    { 
     unsafe 
     { 
      System.TypedReference tr = __makeref(o); 
      System.IntPtr ptr = **(System.IntPtr**) (&tr); 
      return ptr.ToString ("X"); 
     } 
    } 
} 

e poi, in Visual Studio 2012 finestra immediata, durante l'esecuzione nel debugger, tipo:

.load C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll 

che caricherà l'estensione SOS.dll.

È quindi possibile utilizzare GetAddress(x) per ottenere l'indirizzo esadecimale dell'oggetto (per esempio 8AB0CD40), e quindi utilizzare:

!do 8AB0CD40 
!GCRoot -all 8AB0CD40 

alla discarica l'oggetto e trovare tutti i riferimenti all'oggetto.

Ricorda che se il GC è in esecuzione, potrebbe cambiare l'indirizzo dell'oggetto.

Problemi correlati