2014-09-05 1 views
6

Sto cercando di rintracciare una perdita di memoria in un programma C# più grande che genera più thread. Nel processo, ho creato un piccolo programma laterale che sto usando per testare alcune cose di base, e ho trovato un comportamento che non capisco davvero.Perdita di memoria thread

class Program 
{ 
    static void test() 
    { 
    } 

    static void Main(string[] args) 
    { 
     while (true) 
     {    
      Thread test_thread = new Thread(() => test()); 
      test_thread.Start(); 
      Thread.Sleep(20); 
     } 
    } 
} 

In esecuzione questo programma, vedo che l'utilizzo della memoria del programma aumenta costantemente senza fermarsi. In pochi minuti l'utilizzo della memoria supera i 100 MB e continua a salire. Se commento la riga test_thread.Start() ;, la memoria utilizzata dal programma raggiunge circa un paio di megabyte e si livella. Ho anche provato a forzare la garbage collection alla fine del ciclo while usando GC.Collect(), ma non sembrava fare nulla.

Ho pensato che il thread sarebbe stato deinterrogato non appena la funzione è stata completata, permettendo al GC di rimuoverlo, ma questo non sembra accadere. Non devo capire qualcosa di più profondo qui, e gradirei un po 'di aiuto nel correggere questa perdita. Grazie in anticipo!

risposta

9

Questo è in base alla progettazione, il programma di test dovrebbe esibire l'utilizzo della memoria fuori controllo. È possibile visualizzare il motivo sottostante da Taskmgr.exe. Utilizza Visualizza + Seleziona colonne e seleziona "Maniglie". Osserva come il numero di maniglie per il tuo processo è in costante aumento. L'utilizzo della memoria aumenta insieme a quello, riflettendo la memoria non gestita utilizzata dagli oggetti handle.

La scelta di progettazione è stata molto coraggiosa, il CLR utilizza 5 oggetti del sistema operativo per thread. Impianto idraulico, utilizzato per la sincronizzazione. Questi oggetti sono a loro volta usa e getta, la scelta di progettazione era non rendere la classe Thread implement IDisposable. Sarebbe un bel problema per i programmatori .NET, molto difficile effettuare la chiamata a Dispose() al momento giusto. Coraggio che non è stato esibito nel design della classe Task btw, causando un sacco di strizzacervelli e lo general advice not to bother.

Questo è non normalmente un problema in un programma .NET ben progettato. Dove il GC viene eseguito abbastanza spesso da ripulire quegli oggetti del SO. E gli oggetti Thread si stanno creando con parsimonia, usando ThreadPool per thread di esecuzione molto brevi come quelli che usa il programma di test.

Può essere, non possiamo vedere il tuo programma reale. State attenti a trarre troppe conclusioni da un test sintetico. Puoi vedere le statistiche GC con Perfmon.exe, ti dà un'idea se è in esecuzione abbastanza spesso. Un profiler di memoria .NET decente è l'arma di scelta. GC.Collect() è l'arma di backup. Ad esempio:

E lo vedrete rimbalzare avanti e indietro ora, senza mai superare i 4 MB.