2015-05-14 11 views
5

La mia app IIS (.NET 4.0, IIS7) è in continua crescita in memoria e alla fine cade, come se avessi una perdita di memoria.w3wp.exe Garbage Heap è PIENO di spazio oggetti libero e continua a crescere

Così ho preso un DMP mentre era alto circa 1,7 GB e lo aprì in WinDbg.

Il comando dumpheap -stat ha mostrato che, mentre ho avuto una discreta quantità di oggetti nel mucchio, la maggioranza (e un po 'che sta crescendo quando guardando DMP sequenziali) viene etichettato come (> 800 MB) "Libero":

000007feef55b768 46091 2.212.368 System.Data.DataRowView
000007fe9739dda8 10355 2.236.680 Newtonsoft.Json.Serialization.JsonProperty
000007fef4260610 33062 2.644.960 System.Signature
000007fef4242250 41809 4.682.608 System.Reflection.RuntimeMethodInfo
000007fef424f05 8 69232 8847997 System.Byte []
000007fef4241b28 11 9.437.680 System.Double []
000007fef4237ca0 15 9.505.176 System.DateTime []
000007fef424c168 32559 11.009.308 System.Char []
000007fef424dc30 17271 11.795.376 System.Int32 []
000007feef555c48 908 17936672 System.Data.RBTree`1 + Nodo [[System.Int32, mscorlib]] []
000007feef554f58 853 22056952 System.Data.RBTree`1 + Nodo [[System.Data.DataRow, System.Data]] []
000007feef5514b0 541444 51978624 System.Data.DataRow
000007fef424aee0 1550958 132599872 System.String
000007fef422f1b8 183607 178.409.288 System.Object []
0000000000d8b2d0 234017 844.500.226 libero

Così ho poi corse "! Dumpheap -tipo Free", che mi ha dato un sacco di piccoli oggetti liberi (94 byte ciascuno a sii esatto!) E verso l'estremità una coppia di oggetti di larghezza "Free":

00000003098a59b0 0000000000d8b2d0 134 Libera
00000003098c19d0 0000000000d8b2d0 102 Libera
00000003098ffa00 0000000000d8b2d0 54 libero
0000000309a41d98 0000000000d8b2d0 5.961.750 libero
000000041f8a1000 0000000000d8b2d0 24 libero
000000042001b4d0 0000000000d8b2d0 16933078 gratuito
00000004211bf7c8 0000000000d8b2d0 7702 gratuito
00000004212c1600 000000 0000d8b2d0 35.173.374 libero
00000004236b3be0 0000000000d8b2d0 66.886 libero
0000000423cc41e8 0000000000d8b2d0 10.778.318 libero
0000000424768928 0000000000d8b2d0 2.254.734 libero
00000004249ec128 0000000000d8b2d0 21.166.350 libero
000000042600f1e0 0000000000d8b2d0 51366 libero
000000042621bac8 0000000000d8b2d0 114.007.238 libero

Statistics: 
       MT Count TotalSize Class Name 
000007fef31e7460  1   32 System.Net.SafeLocalFree 
0000000000d8b2d0 234017 844500226  Free 
Total 234018 objects 

Notando l'annuncio ripetuto abito di "d8b2d0" Io gestiva un "gcroot d8b2d0!" a cui ho ottenuto il seguente risultato:

0:! '! gcroot -tutti' 000> gcroot d8b2d0
Trovati 0 radici uniche (corsa a vedere tutte le radici).

Quindi ... dopo tutto quello ... Ho masse di oggetti gratuiti bloccati sul mio mucchio che il GC non sta rilasciando. Questo si accumula in circa 2-3 ore. Non vi è alcun altro segno di perdite di memoria dagli oggetti effettivamente digitati. Succede su quasi tutte le nostre macchine virtuali in produzione.

Qualcuno ha qualche idea su come gestire il GC lasciando così tanto spazio libero sull'heap?

Mi ha fatto girare in cerchio per giorni. Quindi il cappello va al genio che può aiutarmi a capire questo!

+0

È un'applicazione Asp.Net? Qualunque struttura o libreria particolare utilizzata? – ljubomir

+0

sì, è asp.net. Sono principalmente DataTable e alcuni WCF locali che usano net.pipe. – StackedActor

+0

Avete qualche codice di interoperabilità o codice che assegna direttamente 'GCHandle's? Sto pensando che forse hai molti oggetti * bloccati * che impediscono la compattazione. –

risposta

1

Grazie al suggerimento sull'uso di PerfView per magicandre1981, e dopo alcuni dump di memoria molto grandi, ho individuato questo problema nell'uso di DataRow.DefaultIfEmpty() in un'espressione Linq. Faceva parte di una funzione di supporto per l'esecuzione di un LeftJoin tra due DataTable.

Con DefaultIfEmpty() nell'enumerazione di DataRow come parte dell'espressione Linq, è possibile ricreare il cielo di memoria che supera a 4 GB + in minuti. La maggior parte di questo sopravvive attraverso la collezione GC Gen2 attraverso il volume puro di ItemArrayObjects in fase di creazione (sia heap di oggetti piccoli che grandi). Questo a sua volta porta ad un valore di memoria impegnato in costante ascesa. La raccolta GC2 non riesce a tenere il passo con il piccolo heap e l'heap di grandi dimensioni soffre di un riutilizzo scarso (se esistente).

Abbiamo preso questa chiamata e la stessa ricreazione non ottiene mai più di 50 MB di memoria impegnata. Ora dobbiamo vedere qual è l'impatto di questo sui nostri join DataTable, ma il mistero dell'heap della memoria è stato risolto!

Grazie per l'aiuto della gente.

0

Se si è certi che la propria app abbia perdite di memoria, suggerirei di avviare l'analisi locale con il profiler della memoria. Questo potrebbe rivelare la fonte del problema più velocemente di analizzare i dump della memoria nella produzione.

+0

Grazie per il suggerimento. Ho passato tutto questo. Non ci sono perdite di memoria, che è ciò che mi ha portato a indagare su un file DMP di memoria. Dall'analisi di cui sopra, si conferma (credo) che in effetti non ci sia una perdita di memoria. Altrimenti quel grosso chunk di 800 MB avrebbe un gcroot o almeno un tipo di oggetto di qualche tipo. Invece è etichettato come * free * ma il GC non lo rilascerà !? – StackedActor