Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Questo articolo illustra come risolvere gli errori di memoria insufficiente in ASP.NET.
Versione originale del prodotto: ASP.NET
Numero KB originale: 2020006
Sintomi
Uno dei problemi più comuni riscontrati in Servizi supporto tecnico Microsoft è OutOfMemoryException
costituito da scenari. È stata quindi creata una raccolta di risorse per facilitare la risoluzione dei problemi di memoria e l'identificazione della causa dei problemi di memoria.
Prima di conoscere i dettagli della risoluzione dei problemi di un OutOfMemoryException
oggetto , è importante comprendere cosa causa questo problema. Contrariamente a quanto credono molti sviluppatori, la quantità di RAM installata non influisce sulla possibilità di un oggetto OutOfMemoryException
. Un sistema operativo a 32 bit può gestire 4 GB di spazio indirizzi virtuale, indipendentemente dalla quantità di memoria fisica installata nella casella. Al di fuori di questo, 2 GB è riservato per il sistema operativo (memoria in modalità kernel) e 2 GB vengono allocati ai processi in modalità utente. I 2 GB allocati per la memoria in modalità kernel vengono condivisi tra tutti i processi, ma ogni processo ottiene i propri 2 GB di spazio indirizzi in modalità utente. Tutto presuppone che l'utente non sia in esecuzione con l'opzione /3gb
abilitata.
Quando un'applicazione deve usare la memoria, riserva un blocco dello spazio indirizzi virtuale e quindi esegue il commit della memoria da tale blocco. È esattamente ciò che fa il Garbage Collector (GC) di .NET Framework quando ha bisogno di memoria per aumentare gli heap gestiti. Quando il GC necessita di un nuovo segmento per l'heap di oggetti di piccole dimensioni (dove si trovano oggetti inferiori a 85 KB), esegue un'allocazione di 64 MB. Quando è necessario un nuovo segmento per l'heap di oggetti di grandi dimensioni, viene eseguita un'allocazione di 16 MB. Queste allocazioni di grandi dimensioni devono essere soddisfatte da blocchi contigui di 2 GB di spazio indirizzi con cui il processo deve funzionare. Se il sistema operativo non è in grado di soddisfare la richiesta del GC per un blocco contiguo di memoria, si verifica un System.OutOfMemoryException
oggetto (OOM).
Note
Un processo a 32 bit in esecuzione in un sistema operativo a 64 bit può gestire 4 GB di memoria in modalità utente e un processo a 64 bit in esecuzione in un sistema operativo a 64 bit può risolvere 8 TB di memoria in modalità utente, quindi un OOM in un sistema operativo a 64 bit non è probabile. È possibile sperimentare un OOM in un processo a 32 bit in esecuzione in un sistema operativo a 64 bit, ma in genere non si verifica finché il processo non usa quasi 3 GB di byte privati.
Esistono due motivi per cui potrebbe essere visualizzata una condizione OOM.
- Il processo usa molta memoria (in genere più di 800 MB in un ambiente a 32 bit).
- Lo spazio degli indirizzi virtuali è frammentato, riducendo la probabilità che un'allocazione contigua di grandi dimensioni abbia esito positivo.
È anche possibile visualizzare una condizione OOM a causa di una combinazione di 1 e 2. Per altre informazioni, vedere Risoluzione dei problemi di System.OutOfMemoryExceptions in ASP.NET.
Quando si verifica un OOM, è possibile notare uno o più dei sintomi seguenti:
L'applicazione si arresta in modo anomalo. Per altre informazioni, vedi Chi è questo ragazzo OutOfMemory e perché fa il mio arresto anomalo del processo quando ho un sacco di memoria lasciato?.
L'applicazione può riscontrare memoria elevata, come indicato da Gestione attività o Monitor prestazioni.
L'elaborazione delle richieste può richiedere molto tempo.
In Internet Information Services (IIS) 7 è possibile usare Risoluzione dei problemi relativi alle richieste non riuscite tramite traccia in IIS 7 per risolvere i problemi relativi alle richieste a esecuzione prolungata.
Gli utenti possono segnalare un messaggio di errore nell'applicazione a causa dell'OOM.
Quando si tratta di determinare la causa di una condizione OOM, si sta effettivamente lavorando per determinare la causa di una situazione di memoria elevata o di uno spazio indirizzi frammentato. Anche se non è possibile documentare tutte le possibili cause di queste situazioni, ci sono alcune cause comuni che vediamo regolarmente.
Le informazioni seguenti illustrano le cause comuni delle condizioni di OOM e le risoluzioni sulla risoluzione di ognuna di queste cause.
Concatenazione di stringhe
Le stringhe in un'applicazione gestita (un'applicazione scritta con .NET Framework) non sono modificabili. Quando un nuovo valore viene assegnato a una stringa, viene creata una copia della stringa esistente. Il nuovo valore viene assegnato alla nuova stringa. In genere non causa problemi. Tuttavia, quando un numero elevato di stringhe viene concatenato, finisce per causare molte più allocazioni di stringhe che uno sviluppatore potrebbe rendersi conto. E può portare a una crescita della memoria e condizioni di OOM.
Per evitare OOM a causa della concatenazione di stringhe, assicurarsi di usare la StringBuilder
classe . Per altre informazioni, vedere Come migliorare le prestazioni di concatenazione delle stringhe in Visual C#.
Frammentazione nell'heap gestito
Il Garbage Collector (GC) in un'applicazione gestita compatta gli heap per ridurre la quantità di frammentazione. Tuttavia, è possibile aggiungere oggetti in un'applicazione gestita. Gli oggetti aggiunti non possono essere spostati durante la compattazione dell'heap. In questo modo, modificare l'indirizzo in corrispondenza del quale si trova l'oggetto. Se un'applicazione aggiunge un numero elevato di oggetti e/o aggiunge oggetti per molto tempo, può causare frammentazione nell'heap gestito. Può portare alla crescita dell'heap gestito più spesso e causare una condizione di OOM.
Si è lavorato per ridurre al minimo le condizioni di OOM a causa dell'aggiunta da .NET Framework 1.0. In ogni versione sono stati apportati miglioramenti incrementali. Tuttavia, esistono ancora modelli di progettazione che è possibile implementare che saranno utili se si ha la necessità di aggiungere oggetti.
Frammentazione nello spazio indirizzo virtuale (VA)
Ogni processo ha una certa quantità di memoria allocata e tale memoria rappresenta lo spazio va per il processo. Se lo spazio VA diventa frammentato, aumenta la probabilità che il GC non riesca a ottenere un grande blocco di memoria contigua per aumentare gli heap gestiti. E può portare a una condizione OOM.
La frammentazione nello spazio VA è spesso causata da uno o più degli scenari seguenti:
Caricamento degli stessi assembly in più domini applicazione.
Se è necessario usare un assembly in più di un'applicazione in esecuzione nello stesso pool di applicazioni, denominare con nome sicuro l'assembly e installarlo nella GAC. In questo modo, assicurarsi che l'assembly venga caricato solo una volta nel processo.
Esecuzione di un'applicazione nell'ambiente di produzione con l'attributo debug dell'elemento
<compilation>
impostato sutrue
.- L'attributo di debug dell'elemento
<compilation>
deve esserefalse
in fase di produzione. - È possibile usare la
<deploy retail="true" />
configurazione per assicurarsi che il debug sia sempre disabilitato nel prodotto. Per altre informazioni, vedere Elemento di distribuzione (schema delle impostazioni ASP.NET).
- L'attributo di debug dell'elemento
Uso dello scripting all'interno di trasformazioni XSL (eXtensible Style Sheet Language) o creazione di
XmlSerializers
.In questo caso, gli assembly dinamici causati da script XSLT (Extensible Style Sheet Language Transformations) o
XmlSerializers
.
Restituire set di dati di grandi dimensioni
Quando si usano dati da un database o da un'altra origine dati, è importante limitare la quantità di dati restituiti. Ad esempio, la memorizzazione nella cache di un risultato della query che restituisce un'intera tabella di database per evitare il costo del recupero di parti di dati dal database quando necessario non è un buon approccio. In questo modo è possibile causare facilmente memoria elevata e causare una condizione OOM. Consentire a un utente di avviare una query simile è un altro modo comune per creare una situazione di memoria elevata. Ad esempio, restituire tutti i dipendenti di una società o tutti i clienti nello stato del Texas con un cognome che inizia con la lettera S.
Limitare sempre la quantità di dati che è possibile restituire da un database. Non consentire query, ad SELECT * FROM. . .
esempio perché non si ha alcun controllo sulla quantità di dati visualizzati nella pagina.
È altrettanto importante assicurarsi di non visualizzare un risultato di dati di grandi dimensioni in elementi dell'interfaccia utente, ad esempio il controllo GridView. Oltre alla memoria necessaria per i dati restituiti, si utilizzeranno anche grandi quantità di dati nelle stringhe e negli elementi dell'interfaccia utente necessari per eseguire il rendering dei risultati. Implementando il paging e convalidando l'input in modo che non vengano restituiti set di dati di grandi dimensioni, è possibile evitare questo problema.
Esecuzione in un ambiente di produzione con traccia abilitata
ASP.NET traccia è una funzionalità potente per la risoluzione dei problemi delle applicazioni. Ma non deve mai essere lasciato in un ambiente di produzione. ASP.NET traccia usa strutture di dati come DataTables
l'archiviazione delle informazioni di traccia e nel tempo possono causare una condizione di memoria elevata che può causare un OOM.
La traccia deve essere disabilitata in un ambiente di produzione. A tale scopo, impostare l'attributo dell'elemento <trace>
su false nel file web.config.enabled
L'abilitazione della distribuzione al dettaglio tramite <deploy retail="true" />
disabilita anche la traccia nelle applicazioni.
Perdita di risorse native
Molte risorse gestite useranno anche risorse native. Poiché GC non pulisce le risorse native, uno sviluppatore è responsabile dell'implementazione e della chiamata del metodo Dispose per pulire le risorse native. Se si usa un tipo che implementa l'interfaccia IDisposable
e non si chiama il Dispose
metodo , si rischia di perdere risorse native e causare una condizione OOM.
Questi oggetti devono implementare l'interfaccia iDisposable
e chiamare il Dispose
metodo su questi oggetti quando non sono più necessari.