Se si tratta di un'applicazione Web ASP.NET tradizionale (WebForms o MVC), il colpevole più probabile è l'archiviazione di sessione. In particolare se si utilizza la memoria di sessione in memoria (che è l'impostazione predefinita) e quindi si utilizza la sessione per mantenere lo stato dell'utente tra le pagine o le chiamate WCF. Questi dati non scompaiono mai fino a quando il server non viene spento, oppure esiste un logout esplicito o lo elimini esplicitamente.
È possibile attenuare un po 'il problema utilizzando un servizio di stato separato o lo stato di memorizzazione nel database. Consulta questo articolo MSDN per le opzioni di archiviazione della sessione. Quindi i dati della sessione verranno caricati dalla memoria esterna quando l'utente fa una richiesta invece di tenerla in memoria. Significativamente, la memorizzazione esternamente dei dati di sessione richiede che i dati siano serializzabili.
Il secondo colpevole è probabile che sia static
di proprietà o campi. Questi sono pigri inizializzati al primo riferimento, ma in seguito non vengono mai raccolti. Se si utilizzano le proprietà statiche per memorizzare i dati nella cache, ad esempio, rimarrà in memoria fino al termine del programma.
Infine, nelle versioni recenti di Visual Studio è possibile vedere l'utilizzo durante il debug localmente o esplicitamente avviare una sessione di profilazione delle prestazioni. Avvia il profiler sulla tua macchina locale con il campionamento della memoria attivato, interagisci con l'applicazione e poi guarda l'analisi che genera sulla memoria e sull'utilizzo della CPU.
Modifica: aggiunta di ulteriori problemi di utilizzo dei dati generali
Esistono pratiche di dati che possono portare a utilizzare troppa memoria. Ad esempio, se si caricano dati da un database in DataSet
o si converte in un elenco di oggetti (compreso l'utilizzo di un ORM). Questo enumera l'intero set di righe restituite e le colloca nella memoria. Per limitare l'utilizzo della memoria, è necessario utilizzare il paging per restituire solo XX risultati alla volta. Oppure usa un DataReader invece di riempire un Dataset (o ORM). Per mantenere la memoria efficiente con DataReader, è necessario: leggere un piccolo batch di record da DataReader, scrivere quel batch direttamente nel flusso di risposta sul servizio Web, ripetere. Se è necessario convertire le righe in oggetti prima di scrivere nel flusso di risposta, allora consiglio il micro-ORM di Dapper. Usa DataReader
internamente e puoi disattivare il buffering e gestire un IEnumerable
di oggetti che non vengono caricati in memoria fino a quando non viene iterato.
Leggere e restituire i file ha lo stesso problema. Se leggi un file in MemoryStream
, l'intero file verrà allocato in memoria. Se si tratta di un file su disco, per risparmiare memoria, è necessario scorrere il flusso di file in blocchi e scriverlo nel flusso di risposta. Le versioni più recenti di .NET hanno Stream.CopyTo
per questo.
Se si utilizzano gli ORM (ad es. Entity Framework) o le librerie DI, questi memorizzano frequentemente gli oggetti nella memoria. Quindi dovrai scavare nella configurazione per vedere se puoi limitarlo o spegnerlo. Gli ORM possono inoltre caricare grafici di oggetti di grandi dimensioni, a seconda di come sono impostati.