2009-11-05 17 views
6

Questo è di gran lunga il software più complesso che ho costruito e ora sembra che stia esaurendo la memoria a un certo punto. Non ho ancora fatto test approfonditi, perché sono un po 'perso come dovrei affrontare il problema a portata di mano.La mia (enorme) applicazione lancia una OutOfMemoryException, e adesso?

HandleCount: 277 
NonpagedSystemMemorySize: 48136 
PagedMemorySize: 1898590208 
PagedSystemMemorySize: 189036 
PeakPagedMemorySize: 1938321408 
VirtualMemorySize: 2016473088 
PeakVirtualMemory: 2053062656 
WorkingSet: 177774592 
PeakWorkingSet: 883834880 
PrivateMemorySize: 1898590208 
PriviligedProcessorTime: 00:00:15.8593750 
UserProcessorTime: 00:00:01.6562500 
TotalProcessorTime: 00:00:17.5156250 
GDI Objects: 30 
User Objects: 27 

Ho un collettore automatizzato globale eccezione che su di eccezione raccoglie le informazioni di cui sopra (usando System.Diagnostics.Process) - insieme con le informazioni sull'eccezione, log e un colpo di schermo - e mi e-mail tutto.

Questo ha funzionato bene in quanto sono stato in grado di collegare i bug in base alle informazioni inviate tramite e-mail. Questo è, fino ad ora. Il software è di decine di migliaia di linee e utilizza risorse gestite e non gestite.

Potrei iniziare a leggere il codice, riga per riga, ma in qualche modo ho la sensazione che questo potrebbe non essere l'approccio migliore per cercare di dedurre il problema di accumulo di memoria.

Come non ho mai fatto prima questo tipo di analisi, come suggeriresti di affrontare questo tipo di problema?

risposta

2

Collegare un debugger e riprodurre l'errore. Lo stack di chiamate all'ora delle eccezioni dovrebbe dirti dove si trova l'errore.

o si ha una perdita di memoria (s), non stai smaltire gli oggetti, o avete bisogno di un hardware migliore :)

+0

IMHO, in questo caso prendere l'eccezione usando il debugger sarà inutile, il danno (probabilmente la perdita di memoria) è già stato fatto altrove. – Naveen

+0

Basta buttare fuori un paio di opzioni. Non posso far male a guardare. – tsilb

+0

tslib ha un punto, a volte è possibile restringere quando si esaurisce la memoria. – Gregory

9

Ci sono un paio di opzioni. Profilatori di memoria dedicati come di RedGate possono essere molto utili per la risoluzione di questo tipo di problemi.

Se non si vuole spendere soldi per uno strumento dedicato, è anche possibile utilizzare WinDbg (parte di Debugging tools for Windows, un download gratuito da Microsoft). Può mostrare l'utilizzo dell'heap per l'heap gestito, i vari heap di AppDomain e così via.

Dai un'occhiata a this blog per suggerimenti sull'utilizzo di WinDbg.

Ricordare che la risoluzione dei problemi della memoria può essere difficile, in quanto di solito non si vede il problema reale ma solo un sintomo. Quindi, a differenza di un arresto anomalo in cui lo stack di chiamate fornisce un'indicazione abbastanza buona dell'origine del problema, la chiamata in stack per un processo con OOM potrebbe rivelarsi molto poco.

Nella mia esperienza devi guardare dove viene utilizzata la memoria. Potrebbe trovarsi nell'heap gestito, nel qual caso devi scoprire se qualcosa è in attesa di istanze più lunghe del necessario. Tuttavia, potrebbe anche essere correlato al caricamento di molti assiemi (in genere assemblaggi generati al volo).

+0

+1 sul profiler della memoria ANTS! – tijmenvdk

+0

+1 per pubblicare qualcosa di utile. – Gregory

+0

ANTS, ottimo strumento. – BennyM

3

Dai un'occhiata a questo articolo MSDN su come rilevare perdite di memoria nelle applicazioni .NET.

Forse ci sono dei problemi in cui la memoria viene allocata e mai raccolta.

1

Il PeakWorkingSet indica il numero comune quando i CLR a 32 bit iniziano a bombardare.

Nonostante ciò che la gente ti dice, e nonostante l'enorme ironia della gestione automatica della memoria, devi essere consapevole di questo e assicurarti di non avvicinarti mai a quel limite su tali sistemi a 32 bit. Molti non ne sono consapevoli e di solito mi piace prendere i loro downstream C# bloat, ma quando si eseguono alcune di tali app su un singolo desktop ci si può aspettare che si verifichi un caos.Basta guardare la parte gestita dello spegnimento VS, è come un treno che passa attraverso un PC.

C'è un MemProfiler gratuito per .NET, usarlo e cercare le radici sospese .. alla fine, e soprattutto quando inizi a trattare con dati di dimensione moderata, dovrai usare il design per lo streaming piuttosto che contare che verrà eseguito su x64 con più RAM.

E avere un dataset c880MB è di dimensioni patetiche in questi giorni .. FATTO!

[Pezzo di C# 3.0 pecore]

10

Forniamo uno strumento per questo.

http://msdn.microsoft.com/en-us/library/ms979205.aspx

CLR Profiler consente di guardare memoria dinamica di un processo e studiare il comportamento del collettore spazzatura. Utilizzando le varie viste nello strumento, è possibile ottenere informazioni utili sull'esecuzione di , allocazione e memoria consumo della propria applicazione.

Utilizzando CLR Profiler, è possibile identificare il codice che alloca troppa di memoria, provoca troppi spazzatura collezioni, e tiene a memoria per troppo tempo.

0

Forse dovresti controllare i luoghi in cui usi le risorse non gestite, per prima cosa. Il problema potrebbe essere che non li rilasci o che non lo fai correttamente.

2

Ho esattamente la stessa applicazione. :) La nostra applicazione utilizza fino a 10 GB di RAM. Questo è ovviamente cattivo. Dopo un po 'di ottimizzazione sono riuscito a ridurre l'utilizzo della memoria circa 50 volte, quindi ora lo stesso set di dati richiede fino a 200 MB. Magia? No. :) Cosa ho fatto:

  1. Alcuni dati sono stati memorizzati più volte nella memoria (più copie). Ho creato una copia di ogni gruppo di dati.
  2. Alcuni dati sono stati memorizzati come string, ma il modo più efficiente è int perché quelle stringhe contenevano solo cifre.
  3. La classe di archiviazione dati principale era . We wrote our own dictionary che non memorizza nessun hash, in quanto l'utilizzo della memoria è diminuito 3 volte su sistemi a 64 bit e 2 volte su sistemi a 32 bit.

Quindi la mia domanda è: qual è la classe/oggetto principale che utilizzi per memorizzare i dati? Che tipo di dati memorizzi?

0

Un sacco di soluzioni utili sono già state suggerite e l'articolo MSDN è molto completo. In combinazione con i suggerimenti di cui sopra farei anche quanto segue;

Correlare l'ora dell'eccezione con il file di registro per vedere cosa stava accadendo al momento dell'eccezione OOM. Se hai poca registrazione a livello di informazioni o di debug ti suggerirei di aggiungere alcune registrazioni in modo da avere un'idea del contesto intorno a questo errore.

L'utilizzo della memoria aumenta gradualmente per un lungo periodo di tempo prima che l'eccezione (ad esempio un processo server che viene eseguito indefinitamente) o un salto di grandi dimensioni aumenti abbastanza rapidamente fino all'eccezione?Ci sono molti thread in esecuzione o solo uno?

Se il primo è vero e l'eccezione non si verifica per un lungo periodo, ciò significherebbe che le perdite di risorse stanno perdendo come sopra indicato. Se il più tardi è vero, un certo numero di cose potrebbe contribuire alla causa, ad es. un ciclo che assegna un sacco di memoria per iterazione, ricevendo un insieme molto ampio di risultati da un servizio ecc. ecc.

In entrambi i casi il file di registro dovrebbe fornire sufficienti informazioni su dove iniziare. Da lì mi sarei assicurato di poter ricreare l'errore emettendo un certo insieme di comandi nell'interfaccia o utilizzando un insieme coerente di input. Successivamente, a seconda dello stato del codice, proverei (con l'uso delle informazioni del file di registro) per creare alcuni test di integrazione che hanno come target la fonte presunta del problema. Questo dovrebbe permetterti di ricreare la condizione di errore molto più velocemente e renderlo molto più facile da trovare poiché il codice su cui ti stai concentrando sarà molto più piccolo.

Altre cose che tendo a fare è un codice di memoria surround con una piccola classe di profiling. Questo può registrare l'utilizzo della memoria nel file di registro e darvi visibilità immediata dei problemi nel registro. La classe può essere ottimizzata in modo che non sia compilata in versioni di rilascio o abbia un piccolo sovraccarico di prestazioni (se hai bisogno di maggiori informazioni contattami). Questo tipo di approccio non funziona bene quando vengono allocati molti thread

Hai menzionato le risorse non gestite presumo che tutto il codice che hai scritto tu/il tuo team sia gestito? Se no e se possibile circonderei i confini non gestiti con una classe di profilazione simile a quella menzionata sopra per escludere le perdite dal codice non gestito o da un'interoperabilità. Anche il blocco di molti puntatori non gestiti può causare la frammentazione dell'heap ma, se non si dispone di codice non gestito, entrambi questi punti possono essere ignorati.

Chiamare esplicitamente il garbage collector in un commento precedente è stato sconsigliato. Anche se raramente dovresti farlo, ci sono dei momenti in cui è valido (cerca gli esempi del blog di Rico Mariani). Un esempio (coperto nel blog menzionato) in cui ho chiamato esplicitamente collect è quando grandi quantità di stringhe sono state restituite da un servizio, inserite in un set di dati e poi legate a una griglia. Anche dopo la chiusura dello schermo, questa memoria non è stata raccolta per qualche tempo. In generale, non dovrebbe essere chiamato esplicitamente in quanto il garbage collector mantiene le metriche su cui basa (tra le altre cose) le collezioni. La chiamata collect invalida esplicitamente queste metriche.

Infine, è generalmente opportuno avere un'idea dei requisiti di memoria dell'applicazione. Ottenere ciò registrando ulteriori informazioni, eseguendo occasionalmente i test di profiler, stress/unità/integrazione. Prendi un'idea dell'impatto che una determinata operazione ha con un livello elevato, ad es. sulla base di un insieme di input all'incirca x sarà assegnato. Comprendo ciò, disconnettendo informazioni dettagliate in punti strategici nel file di registro. Un file di registro gonfio può essere difficile da capire o interpretare.

Problemi correlati