Domanda

Ho un'applicazione che legge da un gran numero di code MSMQ (circa 10000 al momento).Io uso queue.BeginPeek con timeout UInt32.MaxValue per ricevere il messaggio dalla coda.Quando il messaggio appare in coda, lo elaboro e chiamo queue.BeginPeek Ancora.Quindi ascolto tutte le code, ma l'elaborazione dei messaggi viene eseguita su Thread Pool.

Ho notato che l'utilizzo della memoria cresce lentamente (due settimane di lavoro causano una crescita da 200 MB a 800 MB).Dopo aver esaminato il file di dump, vedo la tipica immagine di frammentazione dell'heap con molti oggetti gratuiti (alcuni di essi hanno dimensioni di diversi megabyte).E ci sono oggetti appuntati tra i buchi.

Questa sembra essere una situazione comune quando si lavora con chiamate a codice non gestito, che creano oggetti bloccati.Ma non ho trovato nessuna soluzione su internet.

Quindi la gestione della memoria in .NET è così pura da non consentire di completare nemmeno scenari così semplici, oppure mi sfugge qualcosa?

Modificare : Ho effettuato alcune indagini su applicazioni campione.I buchi (zone di memoria libere, i cosiddetti oggetti liberi) tra gli oggetti bloccati vengono riutilizzati da GC quando si alloca memoria per nuovi oggetti.Ma nella mia applicazione di produzione, gli oggetti appuntati vivono a lungo e finalmente compaiono nella seconda generazione con dei buchi tra loro (perché GC sposta semplicemente il confine che separa le generazioni).Dato che ho pochissimi oggetti normali a lunga vita, vedo questi buchi nella 2a generazione nel file di dump.

Pertanto il consumo di memoria della mia applicazione può aumentare fino a 10000*(dimensione media del foro).(10000 è il numero di code che potranno aumentare anche in futuro).Non ho idee su come risolvere questo problema al momento.L'unico modo è riavviare l'applicazione di tanto in tanto.

Ancora una volta posso solo chiedere: perché .NET non dispone di un heap separato per gli oggetti aggiunti?(forse questa è una domanda da principiante).Al momento vedo che chiamare operazioni asincrone che funzionano con codice non gestito può causare problemi di memoria.

È stato utile?

Soluzione

Dopo aver esaminato il codice sorgente per il wrapper gestito per MSMQ sembra che tu sia inciampato su un vero problema usando l'API.Chiamare BeginPeek creerà una raccolta di proprietà che vengono quindi bloccate prima di passare all'API non gestita.Solo quando viene ricevuto un messaggio sono queste proprietà non vengono visualizzate ma per continuare a ricevere messaggi è necessario chiamare BeginPeek a questo punto che porta alla frammentazione della memoria nel tempo.

Se questa frammentazione è una vera preoccupazione, l'unico hack che posso trovare è ogni ora, è necessario annullare tutte le chiamate a BeginPeek, forzare una raccolta di rifiuti e quindi riprendere le normali operazioni di ascolto.Questo dovrebbe consentire al collettore della spazzatura di gestire la frammentazione.

Altri suggerimenti

Bene, se si tratta di un problema con la lunga durata degli oggetti bloccati, una semplice soluzione sarebbe quella di utilizzare un timeout sul BeginPeek con una durata più breve per impedire loro di passare alla generazione successiva.Dopo ogni timeout e EndPeek puoi riemettere il BeginPeek.A seconda di quando vengono create ed eliminate le proprietà a cui fa riferimento Martin, potrebbe essere necessario ricreare l'oggetto coda (non la coda stessa ovviamente, ma solo il wrapper modificato).Anche se con un po' di fortuna non dovrai arrivare così lontano.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top