La mia applicazione esegue una buona parte della serializzazione binaria e della compressione di oggetti di grandi dimensioni. Non compresso il set di dati serializzato è di circa 14 MB. Compresso è di circa 1,5 MB. Trovo che ogni volta che chiamo il metodo serialize sul mio set di dati il mio contatore di prestazioni di heap di oggetti di grandi dimensioni salta da meno di 1 MB a circa 90 MB. So anche che in un sistema caricato relativamente pesante, di solito dopo un po 'di esecuzione (giorni) in cui questo processo di serializzazione avviene un po' di tempo, è noto che l'applicazione elimina le eccitazioni di memoria quando viene chiamato questo metodo di serializzazione anche se sembra un sacco di memoria. Immagino che la questione sia la frammentazione (anche se non posso dire di essere sicura al 100%, sono abbastanza vicina)Devo chiamare GC.Collect immediatamente dopo aver utilizzato l'heap di oggetti di grandi dimensioni per impedire la frammentazione
La soluzione più semplice a breve termine (credo che cerco sia a breve termine e una risposta a lungo termine) posso pensare di chiamare GC.Collect subito dopo aver terminato il processo di serializzazione. Questo, a mio parere, spazzerà l'oggetto dal LOH e lo farà probabilmente PRIMA che altri oggetti possano essere aggiunti ad esso. Ciò consentirà ad altri oggetti di adattarsi strettamente agli oggetti rimanenti nell'heap senza causare molta frammentazione.
Oltre a questa ridicola allocazione di 90 MB, non credo di avere nient'altro che usi una perdita del LOH. Questa allocazione di 90 MB è anche relativamente rara (intorno ogni 4 ore). Ovviamente avremo ancora l'array da 1,5 MB e forse alcuni altri oggetti serializzati più piccoli.
Qualche idea?
aggiornamento a seguito di buone risposte
Ecco il mio codice che fa il lavoro. In realtà ho provato a cambiarlo per comprimere la serializzazione WHILE in modo che la serializzazione sia serializzata su un flusso allo stesso tempo e non ottengo risultati migliori. Ho anche provato a preallocare il flusso di memoria a 100 MB e provare a utilizzare lo stesso flusso due volte di fila, il LOH sale comunque a 180 MB. Sto usando Process Explorer per monitorarlo. È da pazzi. Penso che proverò l'idea UnmanagedMemoryStream successiva.
Vorrei incoraggiarvi ragazzi a provarlo se non lo volete. Non deve essere questo codice esatto. Basta serializzare un grande insieme di dati e si ottengono risultati sorprendenti (il mio ha un sacco di tavoli, arround 15 e un sacco di archi e colonne)
byte[] bytes;
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter serializer =
new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
System.IO.MemoryStream memStream = new System.IO.MemoryStream();
serializer.Serialize(memStream, obj);
bytes = CompressionHelper.CompressBytes(memStream.ToArray());
memStream.Dispose();
return bytes;
aggiornamento dopo aver provato la serializzazione binaria con UnmanagedMemoryStream
Anche se io serializzato su un UnmanagedMemoryStream il LOH salta alla stessa dimensione. Sembra che non importa quello che faccio, chiamato BinaryFormatter per serializzare questo oggetto di grandi dimensioni utilizzerà il LOH. Per quanto riguarda la pre-allocazione, non sembra essere di grande aiuto. Suppongo di pre-allocare dire che ho preallocato 100 MB, quindi ho serializzato, userà 170 MB. Ecco il codice per questo. Ancora più semplice rispetto al codice sopra
BinaryFormatter serializer = new BinaryFormatter();
MemoryStream memoryStream = new MemoryStream(1024*1024*100);
GC.Collect();
serializer.Serialize(memoryStream, assetDS);
Il GC.Collect() in mezzo c'è solo per aggiornare il contatore delle prestazioni LOH. Vedrai che assegnerà i 100 MB corretti. Ma quando chiamate il serialize, noterete che sembra aggiungere quello sopra il 100 che avete già assegnato.
C'è qualcosa che puoi fare per serializzare direttamente su un 'Stream' invece di usare il LOH come buffer? –