Condividi tramite


Esercizio 2 - Tenere traccia delle allocazioni dei processi in modalità utente

Le allocazioni dell'heap vengono effettuate direttamente tramite api Heap (HeapAlloc, HeapRealloc e allocazioni C/C++, ad esempio nuove, alloc, realloc, calloc) e vengono gestite usando tre tipi di heap:

  1. Heap NT mainline : richieste di allocazione dei servizi di dimensioni inferiori a 64 KB.

  2. Heap a frammentazione bassa : composto da sotto segmenti che consentono di inviare richieste di allocazione dei blocchi di dimensioni fisse.

  3. VirtualAlloc : richieste di allocazione dei servizi di dimensioni superiori a 64 KB.

VirtualAlloc viene usato per allocazioni di memoria dinamiche di grandi dimensioni eseguite direttamente tramite l'API VirtualAlloc . L'utilizzo tipico è in genere per bitmap o buffer. È possibile usare VirtualAlloc per riservare un blocco di pagine e quindi effettuare chiamate aggiuntive a VirtualAlloc per eseguire il commit di singole pagine dal blocco riservato. In questo modo, un processo può riservare un intervallo dello spazio di indirizzi virtuale senza usare l'archiviazione fisica fino a quando non è necessario.

Esistono due concetti da comprendere in questo settore:

  1. Memoria riservata: riserva un intervallo di indirizzi per l'utilizzo, ma non acquisisce risorse di memoria.

  2. Memoria di cui è stato eseguito il commit: assicura che lo spazio di memoria fisica o di file di pagina sia disponibile se viene fatto riferimento agli indirizzi.

In questo esercizio si apprenderà come raccogliere tracce per analizzare il modo in cui un processo in modalità utente alloca la memoria.

L'esercizio è incentrato su un processo fittizio di test denominato MemoryTestApp.exe che alloca la memoria tramite:

  1. API VirtualAlloc per eseguire il commit di buffer di memoria di grandi dimensioni.

  2. Nuovo operatore C ++ per creare un'istanza di oggetti di piccole dimensioni.

È possibile scaricare MemoryTestApp.exe da qui.

Passaggio 1: Raccogliere una traccia virtualAlloc/heap usando WPR

Le allocazioni di memoria di grandi dimensioni sono in genere quelle che influiscono sul footprint di un processo e vengono gestite dall'API VirtualAlloc . È qui che devono iniziare tutte le indagini, ma è anche possibile che un processo si comporti in modo errato con allocazioni più piccole (ad esempio perdite di memoria usando il nuovo operatore in C++, ecc.). La traccia heap diventa utile quando si verifica questa situazione.

Passaggio 1.1: Preparare il sistema per la traccia dell'heap

La traccia heap deve essere considerata facoltativa e eseguita quando l'analisi VirtualAlloc non fornisce alcuna spiegazione pertinente per un problema di utilizzo della memoria. La traccia heap tende a produrre tracce più grandi ed è consigliabile abilitare la traccia solo per i singoli processi che si stanno esaminando.

Aggiungere la chiave del Registro di sistema per il processo di interesse (MemoryTestApp.exe in questo caso); La traccia heap viene quindi abilitata per ogni creazione successiva del processo.

reg add "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /t REG_DWORD /d 1 /f

Passaggio 1.2: Acquisire una traccia usando WPR

In questo passaggio si raccoglierà una traccia usando WPR che contiene dati VirtualAlloc e Heap .

  1. Aprire WPR e modificare la configurazione della traccia.

    1. Selezionare i provider VirtualAlloc e Heap .

    2. Selezionare Generale come scenario di prestazioni.

    3. Selezionare Generale come modalità di registrazione.

      Screenshot del menu opzioni di traccia WPR.

  2. Fare clic su Start per avviare la traccia.

  3. Avviare MemoryTestApp.exee attendere che il processo venga terminato (dovrebbero essere necessari circa 30 secondi).

  4. Tornare a WPR, salvare la traccia e aprirla con Windows analizzatore prestazioni (WPA).

  5. Aprire il menu Traccia e selezionare Configura percorso simboli.

    • Specificare il percorso della cache dei simboli. Per altre informazioni sui simboli, vedere la pagina Supporto simboli su MSDN.
  6. Aprire il menu Traccia e selezionare Carica simboli.

È ora disponibile una traccia che contiene tutti i modelli di allocazione di memoria per il processo diMemoryTestApp.exe durante la sua durata.

Passaggio 2: Esaminare le allocazioni dinamiche di VirtualAlloc

I dati VirtualAlloc dettagliati vengono esposti tramite il grafico "Durata commit VirtualAlloc" in WPA. Le colonne chiave di interesse sono le seguenti:

Colonna Descrizione
Processo

Nome del processo che esegue allocazioni di memoria tramite VirtualAlloc.

Commit Stack

Stack di chiamate che mostra il percorso del codice che porta all'allocazione della memoria.

Ora commit

Timestamp di quando è stata allocata la memoria.

Tempo di decommit

Timestamp di quando la memoria è stata liberata.

Impatto sulle dimensioni

Le dimensioni delle allocazioni in sospeso o la differenza di dimensione tra l'inizio e la fine dell'intervallo di tempo selezionato. Questa dimensione viene modificata in base alla porta di visualizzazione selezionata.

Il valore Dimensioni di impatto sarà zero se tutta la memoria allocata da un processo viene liberata entro la fine dell'intervallo visualizzato in WPA.

Dimensione

Somma cumulativa di tutte le allocazioni durante l'intervallo di tempo selezionato.

Seguire questa procedura per analizzare MemoryTestApp.exe

  1. Trovare il grafico VirtualAlloc Commit Lifetimes nella categoria Memoria di Graph Explorer.

  2. Trascinare e rilasciare VirtualAlloc Commit Lifetimes (Durata commit VirtualAlloc ) nella scheda Analisi .

  3. Organizzare la tabella per visualizzare queste colonne. Fare clic con il pulsante destro del mouse sulle intestazioni di colonna per aggiungere o rimuovere colonne.

    1. Processo

    2. Tipo di impatto

    3. Commit Stack

    4. Ora di commit e ora di decommit

    5. Numero

    6. Impatto su dimensioni e dimensioni

  4. Trovare MemoryTestApp.exe nell'elenco dei processi.

  5. Applicare un filtro per mantenere solo MemoryTestApp.exe sul grafico.

    • Fare clic con il pulsante destro del mouse e scegliere Filtra in selezione.

Screenshot che mostra come filtrare i risultati.

Il viewport di analisi dovrebbe essere simile al seguente:

Grafico di esempio dell'aspetto dei dati quando vengono filtrati.

Nell'esempio precedente, due valori sono di interesse:

  • Dimensioni di 126 MB: indica che MemoryTestApp.exe allocato un totale di 125 MB nel corso della sua durata. Rappresenta la somma cumulativa di tutte le chiamate API VirtualAlloc effettuate dal processo e dalle relative dipendenze.

  • Impatto sulle dimensioni di 0 MB: indica che tutta la memoria allocata dal processo viene liberata entro la fine dell'intervallo di tempo attualmente analizzato. Il sistema non ha subito un aumento dell'utilizzo costante della memoria dello stato.

Passaggio 2.1: Analizzare l'utilizzo della memoria a stato stabile

Quando si esamina l'allocazione di memoria, è consigliabile provare a rispondere alla domanda: "Perché l'utilizzo della memoria a stato stabile cresce per questo scenario?" Nell'esempio MemoryTestApp.exe è possibile notare che ha circa 10 MB di memoria a stato stabile allocata all'inizio e quindi aumenta fino a 20 MB a metà strada.

Screenshot dei dati di esempio che mostrano l'utilizzo della memoria.

Per esaminare questo comportamento, restringere lo zoom intorno all'intervallo di tempo in cui si verifica l'aumento improvviso al centro della traccia.

Screenshot che mostra come eseguire lo zoom dei dati.

Il riquadro di visualizzazione dovrebbe essere simile al seguente.

Screenshot dei dati di esempio dopo l'applicazione dell'opzione di zoom del grafico con VirtualAlloc Commit LifeTimes e Commit in attesa per processo

Come si può notare, la dimensione che influisce è ora di 10 MB. Ciò significa che, tra l'inizio e la fine dell'intervallo di tempo analizzato, si verifica un aumento di 10 MB nell'utilizzo della memoria a stato stabile.

  1. Ordinare in base all'impatto sulle dimensioni facendo clic sull'intestazione di colonna.

  2. Espandere la rigaMemoryTestApp.exe (nella colonna Processo ).

  3. Espandere la riga Impatto (nella colonna Tipo di impatto ).

  4. Esplorare lo stack di commit del processo fino a trovare la funzione che ha allocato 10 MB di memoria.

    Screenshot della tabella dei dati di esempio che mostra il numero di riga, il processo, il tipo di impatto, lo stack di commit, l'ora di commit, il tempo di decommit, il conteggio e le dimensioni di impatto

In questo esempio, la funzione Main di MemoryTestApp.exe alloca 10 MB di memoria al centro del carico di lavoro chiamando direttamente VirtualAlloc. Nel mondo reale, lo sviluppatore dell'applicazione deve determinare se l'allocazione è ragionevole o se il codice potrebbe essere riorganiato per ridurre al minimo l'aumento dell'utilizzo della memoria a stato stabile.

È ora possibile annullare l'attivazione del riquadro di visualizzazione in WPA.

Screenhsot del menu di unzoom.

Passaggio 2.2: Analizzare l'utilizzo della memoria temporanea (o picco)

Quando si esaminano le allocazioni di memoria, è consigliabile provare a rispondere alla domanda: "Perché esiste un picco temporaneo nell'utilizzo della memoria per questa parte dello scenario?" Le allocazioni temporanee causano picchi di utilizzo della memoria e possono causare la frammentazione e il push di contenuto prezioso dalla cache standby del sistema quando si verifica un utilizzo elevato della memoria.

Nell'esempio MemoryTest è possibile notare che sono presenti 10 picchi diversi di utilizzo della memoria (di 10 MB) uniformemente sparsi nella traccia.

Screenshot del grafico che mostra i dati di utilizzo della memoria.

Restringere lo zoom agli ultimi quattro picchi, per concentrarsi su un'area più piccola di interesse e ridurre il rumore da comportamenti non rilevanti.

Screenshot dell'opzione di zoom.

Il riquadro di visualizzazione sarà simile al seguente:

Screenshot del grafico che mostra i dati di utilizzo della memoria usando l'opzione zoom.

  1. Ordinare in base alle dimensioni facendo clic sull'intestazione di colonna.

  2. Espandere la rigaMemoryTestApp.exe (nella colonna Processo ).

  3. Fare clic sulla riga Temporanea (nella colonna Tipo di impatto ).

    • Questa opzione deve essere evidenziata in blu per tutti i picchi di utilizzo della memoria nel riquadro di visualizzazione.
  4. Si noti il valore delle diverse colonne:

    1. Count = 4: indica che durante tale intervallo di tempo sono state effettuate quattro allocazioni di memoria temporanee.

    2. Impatto sulle dimensioni = 0 MB: indica che tutte e quattro le allocazioni di memoria temporanee sono state liberate entro la fine dell'intervallo di tempo.

    3. Dimensioni = 40 MB: indica che la somma di tutte e quattro le allocazioni di memoria temporanee è pari a 40 MB di memoria.

  5. Esplorare lo stack di commit del processo fino a trovare le funzioni che hanno allocato 40 MB di memoria.

    Screenshot dei dati di utilizzo della memoria.

In questo esempio la funzione Main di MemoryTestApp.exe chiama una funzione denominata Operation1, che a sua volta chiama una funzione denominata ManipulateTemporaryBuffer. Questa funzione ManipulateTemporaryBuffer chiama quindi virtualAlloc quattro volte, creando e liberando ogni volta un buffer di memoria di 10 MB. I buffer durano solo 100 ms ciascuno. L'allocazione e i tempi liberi dei buffer sono rappresentati dalle colonne Ora commit e Ora di decommite .

Nel mondo reale, lo sviluppatore dell'applicazione determinerà se tali allocazioni di buffer temporanei temporanei di breve durata sono necessarie o se possono essere sostituite usando un buffer di memoria permanente per l'operazione.

È ora possibile annullare l'attivazione del riquadro di visualizzazione in WPA.

Passaggio 3: Esaminare le allocazioni dinamiche dell'heap

Finora, l'analisi si è concentrata solo sulle allocazioni di memoria di grandi dimensioni gestite dall'API VirtualAlloc . Il passaggio successivo consiste nel determinare se si verificano problemi con altre allocazioni di piccole dimensioni effettuate dal processo, usando inizialmente i dati dell'heap raccolti.

I dati dell'heap dettagliati vengono esposti tramite il grafico "Allocazioni heap" in WPA. Le colonne chiave di interesse sono le seguenti:

Colonna Descrizione
Processo Nome del processo che esegue l'allocazione di memoria.
Handle

Identificatore dell'heap utilizzato per gestire l'allocazione.

È possibile creare heap, quindi potrebbero essere presenti più handle heap per il processo.

Tra elementi sovrapposti Stack di chiamate che mostra il percorso del codice che porta all'allocazione della memoria.
Tempo di allocazione Timestamp di quando è stata allocata la memoria.
Impatto sulle dimensioni Le dimensioni delle allocazioni in sospeso o la differenza tra l'inizio e la fine del riquadro di visualizzazione selezionato. Questa dimensione viene modificata in base all'intervallo di tempo selezionato.
Dimensione Somma cumulativa di tutte le allocazioni/deallocazione.

Seguire questa procedura per analizzare MemoryTestApp.exe

  1. Trovare il grafico Allocazioni heap nella categoria Memoria di Graph Explorer.

  2. Trascinare e rilasciare le allocazioni dell'heap nella scheda Analisi .

  3. Organizzare la tabella per visualizzare le colonne seguenti:

    1. Processo

    2. Handle

    3. Tipo di impatto

    4. Tra elementi sovrapposti

    5. AllocTime

    6. Numero

    7. Impatto su dimensioni e dimensioni

  4. Trovare MemoryTestApp.exe nell'elenco dei processi.

  5. Applicare un filtro per mantenere solo MemoryTestApp.exe sul grafico.

    • Fare clic con il pulsante destro del mouse e scegliere Filtra in selezione.

Il riquadro di visualizzazione sarà simile al seguente:

Screenshot dei dati di esempio che mostra il grafico Delle allocazioni heap delle dimensioni in sospeso per processo e handle

In questo esempio è possibile notare che uno degli heap aumenta costantemente nelle dimensioni nel tempo a una velocità costante. In tale heap sono presenti 1200 allocazioni di memoria, che rappresentano 130 KB di memoria usata entro la fine dell'intervallo.

  1. Zoom avanti su un intervallo più piccolo (ad esempio, 10 secondi) al centro della traccia.

  2. Espandere l'handle head che mostra la quantità maggiore di allocazioni , come illustrato nella colonna Dimensioni di impatto .

  3. Espandere il tipo di impatto .

  4. Esplorare lo stack di processi fino a trovare la funzione responsabile dell'allocazione di tutta questa memoria.

    Screenshot della tabella dei dati di esempio che mostra Process, Handle, Impacting Type, Stack, AllocTime, Count, Impacting Size and Size con due righe selezionate

In questo esempio la funzione Main di MemoryTestApp.exe chiama una funzione denominata InnerLoopOperation. Questa funzione InnerLoopOperation alloca quindi 40 byte di memoria 319 volte tramite il nuovo operatore C++. Questa memoria rimane allocata fino al termine del processo.

Nel mondo reale, lo sviluppatore di applicazioni deve quindi determinare se questo comportamento implica una possibile perdita di memoria e risolvere il problema.

Passaggio 4: Pulire il sistema di test

Al termine dell'analisi, è necessario pulire il Registro di sistema per assicurarsi che la traccia dell'heap sia disabilitata per il processo. Eseguire questo comando in un prompt dei comandi con privilegi elevati:

reg delete "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\MemoryTestApp.exe" /v TracingFlags /f