Come faccio a eseguire il debug dei problemi di memoria su un server condiviso?

3

Ho un sito Web ASP.NET su un server condiviso. Il sito è principalmente utilizzato per ospitare alcuni servizi WCF utilizzati da un'applicazione desktop.

Abbiamo avuto un problema in quanto il server ha smesso di rispondere e la società di hosting ha affermato che i registri del pool di applicazioni mostravano che avevamo raggiunto il limite di memoria (500Mb), che ha causato il riciclo del pool di applicazioni.

Devo scoprire che cosa sta causando il problema di memoria. Il codice è tutto C #, nessuna chiamata non gestita. È un'applicazione a livelli, con il layer WCF molto sottile, che passa fondamentalmente le chiamate al livello di servizio. Il livello di servizio utilizza un livello di repository per eseguire l'accesso al database (tramite Entity Framework) e tutte le dipendenze vengono iniettate. Non so se ci sono altri dettagli tecnici rilevanti. Se è così, si prega di commentare e li aggiungerò in.

Ci sono solo circa tre utenti per l'applicazione, quindi è molto improbabile che sia una dimensione d'uso pura.

Poiché si tratta di un server condiviso, non ho accesso diretto ad esso, quindi non posso usare alcun tool di profiling che richiede l'associazione al processo ecc. Tutto ciò che faccio deve essere scritto nel C # stesso.

Ho pensato di creare localmente un ambiente di test, e di colpirlo con un sacco di chiamate di servizio, ma poiché non so esattamente cosa stiano facendo gli utenti, è difficile sapere se riprodurrei lo scenario di produzione.

È possibile vedere quale memoria sta usando il sito Web dal codice C #, così posso vedere cosa sta succedendo sul server di produzione?

    
posta Avrohom Yisroel 11.09.2017 - 19:45
fonte

2 risposte

2

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.

    
risposta data 12.09.2017 - 19:18
fonte
1

Suggerisco di costruire una macchina simile nel tuo ambiente di sviluppo o di test e riprodurre la perdita di memoria su di essa. Quindi puoi allegare un profiler ai tuoi processi .net per catturare la perdita. Suggerisco dotMemory profiler per questo scopo. Ecco un articolo su come identificare la perdita di memoria nelle applicazioni .NET:

link

    
risposta data 12.09.2017 - 23:28
fonte

Leggi altre domande sui tag