Condividi tramite


Misurare l'utilizzo della memoria in Visual Studio (C#, Visual Basic, C++, F#)

Trova perdite di memoria e inefficienze mentre esegui il debug utilizzando lo strumento diagnostico integrato nel debugger Utilizzo Memoria. Lo strumento Utilizzo memoria consente di acquisire uno o più *snapshot* dell'heap della memoria gestita e nativa, per comprendere come i tipi di oggetto influenzano l'utilizzo della memoria. È anche possibile analizzare l'utilizzo della memoria senza un debugger collegato o specificando come destinazione un'app in esecuzione. Per altre informazioni, vedere Eseguire strumenti di profilatura nelle build di rilascio o di debug. Per informazioni sulla scelta dello strumento di analisi della memoria migliore per le proprie esigenze, vedere Scegliere uno strumento di analisi della memoria.

Sebbene sia possibile raccogliere snapshot di memoria in qualsiasi momento nello strumento Utilizzo memoria, è possibile usare il debugger di Visual Studio per controllare l'esecuzione dell'applicazione durante l'analisi dei problemi di prestazioni. L'impostazione di punti di interruzione, passaggio, Interrompi tutto e altre azioni del debugger consente di concentrare le indagini sulle prestazioni sui percorsi di codice più rilevanti. L'esecuzione di queste azioni mentre l'app è in esecuzione può eliminare il rumore dal codice che non interessa e può ridurre significativamente il tempo necessario per diagnosticare un problema.

Importante

Gli strumenti di diagnostica integrati nel debugger sono supportati per lo sviluppo .NET in Visual Studio, tra cui ASP.NET, ASP.NET Core, sviluppo nativo/C++ e app in modalità mista (.NET e native).

In questa esercitazione si eseguiranno le seguenti attività:

  • Catturare istantanee di memoria
  • Analizzare i dati di utilizzo della memoria

Se Utilizzo della Memoria non fornisce i dati necessari, altri strumenti di profilatura nel Profiler delle Prestazioni forniscono diversi tipi di informazioni che potrebbero esserti utili. In molti casi, il collo di bottiglia delle prestazioni dell'applicazione può essere causato da un elemento diverso dalla memoria, ad esempio la CPU, il rendering dell'interfaccia utente o il tempo delle richieste di rete.

Nota

supporto dell'allocatore personalizzato Il profiler di memoria nativa funziona raccogliendo dati dell'evento ETW generati durante l'esecuzione. Gli allocatori in CRT e Windows SDK sono stati annotati a livello di origine in modo che i dati di allocazione possano essere acquisiti. Se si scrivono allocatori personalizzati, tutte le funzioni che restituiscono un puntatore alla memoria heap appena allocata possono essere decorate con __declspec(allocatore), come illustrato in questo esempio per myMalloc:

__declspec(allocator) void* myMalloc(size_t size)

Raccogliere i dati sull'utilizzo della memoria

  1. Aprire il progetto di cui si vuole eseguire il debug in Visual Studio e impostare un punto di interruzione nell'app nel punto in cui si vuole iniziare a esaminare l'utilizzo della memoria.

    Se si dispone di un'area in cui si sospetta un problema di memoria, impostare il primo punto di interruzione prima che si verifichi il problema di memoria.

    Mancia

    Poiché può essere difficile acquisire il profilo di memoria di un'operazione che ti interessa quando l'app alloca e dealloca frequentemente la memoria, imposta i punti di interruzione all'inizio e alla fine dell'operazione (o passa attraverso l'operazione) per trovare il punto esatto in cui la memoria è cambiata.

  2. Impostare un secondo punto di interruzione alla fine della funzione o dell'area di codice che si vuole analizzare (o dopo che si verifica un sospetto problema di memoria).

  3. La finestra strumenti di diagnostica compare automaticamente a meno che non sia stata disattivata. Per visualizzare di nuovo la finestra, fare clic su Debug>Windows>Mostra strumenti di diagnostica.

  4. Scegliere Utilizzo memoria con l'impostazione Seleziona strumenti sulla barra degli strumenti.

    screenshot degli strumenti di diagnostica.

    screenshot degli strumenti di diagnostica.

  5. Fare clic su Debug/Avvia debug oppure Start sulla barra degli strumenti oppure F5).

    Al termine del caricamento dell'app, viene visualizzata la visualizzazione Riepilogo degli strumenti di diagnostica.

    screenshot della scheda Riepilogo strumenti di diagnostica.

    Nota

    Poiché la raccolta dei dati di memoria può influire sulle prestazioni di debug delle app in modalità nativa o mista, gli snapshot di memoria sono disabilitati per impostazione predefinita. Per abilitare gli snapshot nelle app in modalità nativa o mista, avviare una sessione di debug (tasto di scelta rapida: F5). Quando viene visualizzata la finestra Strumenti di diagnostica, scegliere la scheda Utilizzo memoria e quindi scegliere Profilatura heap.

    Schermata dell'opzione Abilita istantanee.

    Stop (tasto di scelta rapida: MAIUSC+F5) e riavvia il debugging.

    screenshot della scheda Riepilogo strumenti di diagnostica.

    Nota

    Poiché la raccolta dei dati di memoria può influire sulle prestazioni di debug delle app in modalità nativa o mista, gli snapshot di memoria sono disabilitati per impostazione predefinita. Per abilitare gli snapshot nelle app in modalità nativa o mista, avviare una sessione di debug (tasto di scelta rapida: F5). Quando viene visualizzata la finestra Strumenti di diagnostica, scegliere la scheda Utilizzo memoria e quindi scegliere heap profiling.

    screenshot dell'opzione Abilita snapshot.

    Arresta (tasto di scelta rapida: MAIUSC+F5) e riavvia il debug.

  6. Per creare uno snapshot all'inizio della sessione di debug, scegliere Crea snapshot sulla barra degli strumenti di riepilogo utilizzo memoria. Può essere utile impostare anche un punto di interruzione.

    screenshot del pulsante Crea snapshot.

    screenshot del pulsante Crea snapshot.

    Consiglio

    Per creare una linea di base per i confronti di memoria, è consigliabile creare uno snapshot all'inizio della sessione di debug.

  7. Esegui lo scenario che causerà l'attivazione del primo punto di interruzione.

  8. Mentre il debugger è sospeso al primo punto di interruzione, seleziona Crea snapshot sulla barra degli strumenti di riepilogo Utilizzo Memoria.

  9. Premere F5 per eseguire l'app al secondo punto di interruzione.

  10. Ora, creare un altro snapshot.

    A questo punto, è possibile iniziare ad analizzare i dati.

    Se si verificano problemi durante la raccolta o la visualizzazione dei dati, consulta Risolvere gli errori di profilazione e risolvere i problemi.

Analizzare i dati di utilizzo della memoria

Le righe della tabella di riepilogo Utilizzo memoria elencano gli snapshot acquisiti durante la sessione di debug e forniscono collegamenti a visualizzazioni più dettagliate.

screenshot della tabella Utilizzo memoria.

screenshot della tabella Utilizzo memoria.

Il nome della colonna dipende dalla modalità di debug scelta nelle proprietà del progetto: .NET, native o mixed (sia .NET che native).

  • Nella colonna Objects (Diff) (.NET) o Allocations (Diff) (C++) viene visualizzato il numero di oggetti in .NET o in memoria nativa quando è stato creato lo snapshot.

  • La colonna dimensioni heap (Diff) visualizza il numero di byte nell'heap .NET e gli heap nativi

Dopo aver acquisito più snapshot, le celle della tabella di riepilogo includono la modifica nel valore tra lo snapshot di riga e lo snapshot precedente.

Per analizzare l'utilizzo della memoria, fare clic su uno dei collegamenti che apre un report dettagliato sull'utilizzo della memoria:

  • Per visualizzare i dettagli della differenza tra lo snapshot corrente e lo snapshot precedente, scegli il link di modifica a sinistra della freccia (Aumento Utilizzo Memoria). Una freccia rossa indica un aumento dell'utilizzo della memoria e una freccia verde indica una diminuzione.

Consiglio

Per identificare più rapidamente i problemi di memoria, i report diff vengono ordinati in base ai tipi di oggetto che hanno aumentato il numero complessivo (fare clic sul collegamento di modifica nella colonna Oggetti (Diff)) o che hanno aumentato la dimensione complessiva dell'heap (fare clic sul collegamento di modifica in colonna Dimensioni heap (Diff)).

  • Per visualizzare i dettagli solo dello snapshot selezionato, fare clic sul collegamento non modifica.

    Il report viene visualizzato in una finestra separata.

Report sui tipi gestiti

Scegliere il collegamento corrente di una cella Objects (Diff) nella tabella di riepilogo Utilizzo memoria.

Screenshot del report del tipo gestito.

Nota

Per il codice .NET, l'icona View Instances (L'icona dell'istanza nella colonna Tipo di oggetto) è disponibile solo quando si usa lo strumento Utilizzo memoria integrato al debugger o quando si apre un'istantanea dell'heap e si sceglie il Debug della memoria gestita .

Il riquadro superiore mostra il numero e le dimensioni dei tipi nello snapshot, incluse le dimensioni di tutti gli oggetti a cui fa riferimento il tipo (dimensione inclusiva).

Nell'albero Percorsi alla radice nel riquadro inferiore vengono visualizzati gli oggetti che fanno riferimento al tipo selezionato nel riquadro superiore. .NET Garbage Collector pulisce la memoria per un oggetto solo quando l'ultimo tipo a cui fa riferimento è stato rilasciato. Per altre informazioni sull'uso dell'albero percorsi di radice, vedere Analizzare il percorso critico alla radice.

Screenshot del report del tipo gestito.

Il riquadro superiore mostra il numero e le dimensioni dei tipi nello snapshot, incluse le dimensioni di tutti gli oggetti a cui fa riferimento il tipo (dimensione inclusiva).

Nell'albero Percorsi alla radice nel riquadro inferiore vengono visualizzati gli oggetti che fanno riferimento al tipo selezionato nel riquadro superiore. .NET Garbage Collector pulisce la memoria per un oggetto solo quando l'ultimo tipo a cui fa riferimento è stato rilasciato.

Nell'albero Tipi a cui si fa riferimento vengono visualizzati i riferimenti contenuti nel tipo selezionato nel riquadro superiore.

Screenshot del report sugli Oggetti di Riferimento.

Nell'albero dei tipi referenziati vengono visualizzati i riferimenti detenuti dal tipo selezionato nel riquadro superiore.

Screenshot del report Oggetti di riferimento.

Per visualizzare le istanze di un tipo selezionato nel riquadro superiore, fare clic sull'icona Visualizza Istanze accanto al tipo di oggetto.

Screenshot della visualizzazione Istanze nello strumento Utilizzo della memoria.

La visualizzazione delle istanze mostra le istanze dell'oggetto selezionato nello snapshot nel riquadro superiore. Nel riquadro Percorsi verso la Radice e Oggetti a cui si fa Riferimento, vengono visualizzati gli oggetti che fanno riferimento all'istanza selezionata e i tipi a cui l'istanza selezionata fa riferimento. Quando il debugger è fermo nel punto in cui è stato creato lo snapshot, è possibile passare il puntatore del mouse sulla cella di valore per visualizzare i valori dell'oggetto in una descrizione comando.

Screenshot della visualizzazione Istanze nello strumento Utilizzo memoria.

La visualizzazione delle istanze di mostra le istanze dell'oggetto selezionato nello snapshot nel riquadro superiore. Nel riquadro Percorsi verso radice e Oggetti di riferimento vengono visualizzati gli oggetti che fanno riferimento all'istanza selezionata e i tipi a cui l'istanza selezionata fa riferimento. Quando il debugger viene arrestato nel punto in cui è stato creato lo snapshot, è possibile passare il mouse sopra la cella Valore per visualizzare i valori dell'oggetto in una descrizione comando.

Report sui tipi di dati nativi

Scegliere il collegamento corrente di una cella Allocazioni (Diff) o Dimensione heap (Diff) nella tabella di riepilogo Utilizzo memoria della finestra Strumenti di diagnostica.

La Vista Tipi è la visualizzazione del numero e delle dimensioni dei tipi nello snapshot.

  • Scegliere l'icona Visualizza istanze accanto a un tipo selezionato per visualizzare informazioni sugli oggetti del tipo selezionato nello snapshot.

    La vista istanze mostra ogni istanza del tipo selezionato. Se si seleziona un'istanza, viene visualizzato lo stack di chiamate che ha portato alla creazione dell'istanza nel riquadro stack di chiamate di allocazione. Queste informazioni sono disponibili solo durante il debug.

    screenshot della visualizzazione Istanze e dello stack di chiamate di allocazione.

  • Scegliere l'icona delle istanze (L'icona dell'istanza nella colonna Tipo di oggetto) di un tipo selezionato per visualizzare informazioni sugli oggetti del tipo selezionato nello snapshot.

    La vista Istanze mostra ogni istanza del tipo selezionato. Selezionando un'istanza, viene visualizzato lo stack di chiamate che ha portato alla creazione dell'istanza nel riquadro Allocazione Stack di Chiamate.

    istantanea della visualizzazione delle Istanze e del pannello della pila delle chiamate di allocazione.

  • Scegliere Stack per visualizzare lo stack di allocazione per il tipo selezionato.

    Screenshot della visualizzazione Stacks.

  • Scegliere Visualizzazione stack nell'elenco modalità di visualizzazione per visualizzare lo stack di allocazione per il tipo selezionato.

    Screenshot della visualizzazione Stack.

Informazioni dettagliate sull'utilizzo della memoria

Per la memoria gestita, lo strumento di Analisi della Memoria offre anche molteplici potenti approfondimenti automatici predefiniti. Selezionare la scheda Insights nei report Tipi gestiti e vengono visualizzate le informazioni dettagliate generate automaticamente, ad esempio Stringhe duplicate, matrici sparsee perdite di gestori di eventi .

Screenshot della visualizzazione delle informazioni dettagliate nello strumento Utilizzo memoria.

La sezione stringhe duplicate mostra l'elenco di stringhe che vengono allocate più volte nell'heap. Inoltre, questa sezione mostra la memoria totale sprecata, ovvero il (numero di istanze - 1) volte la dimensione della stringa.

La sezione matrici sparse mostra le matrici che sono principalmente riempite con zero elementi, che possono risultare inefficienti in termini di prestazioni e utilizzo della memoria. Lo strumento di analisi della memoria rileverà automaticamente queste matrici e mostrerà la quantità di memoria sprecato a causa di questi valori zero.

La sezione Event Handler Leaks, disponibile in Visual Studio 2022 versione 17.9 Preview 1, mostra potenziali perdite di memoria che possono verificarsi quando un oggetto sottoscrive l'evento di un altro oggetto. Se l'emittente dell'evento vive più a lungo del sottoscrittore, il sottoscrittore resta attivo anche se non vi sono altri riferimenti. Ciò può causare perdite di memoria, in cui la memoria inutilizzata non viene liberata correttamente, causando l'uso di maggiore e maggiore memoria nell'applicazione nel tempo.

Alcuni tipi sono noti per avere campi che possono essere letti per determinare le dimensioni della memoria nativa che contengono. La scheda informazioni dettagliate mostra i nodi di memoria nativa falsi nel grafico degli oggetti, che vengono trattenuti dai relativi oggetti padre in modo che l'interfaccia utente li riconosca e ne visualizzi le dimensioni e il grafico di riferimento.

Screenshot della visualizzazione delle informazioni dettagliate native nello strumento Utilizzo memoria.

Report di modifica (diff)

  • Scegliere il collegamento di modifica in una cella della tabella di riepilogo della scheda Utilizzo memoria nella finestra Strumenti di diagnostica.

    Screenshot di Scegliere un collegamento di modifica in una cella.

    Screenshot di Scegliere un collegamento di modifica in una cella.

  • Scegliere un'istantanea nell'elenco 'Confronta con' di un report gestito o nativo.

    Screenshot di Scegliere uno snapshot dall'elenco Confronta a.

    Screenshot di scegli uno snapshot dall'elenco Confronta con.

Il report delle modifiche aggiunge colonne (contrassegnate con (Diff)) al report di base che mostra la differenza tra il valore dello snapshot di base e lo snapshot di confronto. Ecco come potrebbe essere presentato un rapporto di differenze per la visualizzazione di tipo nativo:

screenshot della visualizzazione Diff dei tipi nativi.

Il riquadro superiore mostra il numero e le dimensioni dei tipi nello snapshot, incluse le dimensioni di tutti gli oggetti a cui fa riferimento il tipo (dimensione inclusiva).

Blog e video

Analizzare CPU e memoria durante il debug

blog di visual C++ : Profilatura della memoria in Visual C++ 2015

Passaggi successivi

In questa esercitazione si è appreso come raccogliere e analizzare i dati di utilizzo della memoria. Se hai già completato il tour del profiler, potresti voler leggere un approccio generale per l'ottimizzazione del codice usando gli strumenti di profilazione.

In questa esercitazione si è appreso come raccogliere e analizzare i dati di utilizzo della memoria durante il debug. Potresti voler saperne di più sull'analisi dell'utilizzo della memoria nelle build di rilascio usando il Profiler Prestazioni.