Memoria Paged e NonPaged Pool – Come risolvere un memory leak

In questo post vedremo come risolvere un leak di memoria e identificare il driver responsabile.
Vi consiglio di leggere il post Memoria Paged e NonPaged Pool – Come identificare un memory leak per verificare che effettivamente siamo in presenza di un leak di memoria.

Utilizzare il PoolMon

L’allocazione di una quantità di byte in una delle memorie Pool utilizza un sistema di tagging. Un TAG è un identificativo di quattro byte associato ad ogni porzione di memoria Pool allocata.

Il TAG viene specificato da un driver, durante l’allocazione della memoria, attraverso la routine ExAllocatePoolWithTag. I seguenti tre parametri, devono essere specificati durante la chiamata a questa routine:

  • PoolType: Il tipo di memoria Pool da allocare (Paged o NonPaged)
  • NumberofBytes: Il numero di byte da allocare con la richiesta
  • TAG: il Pool TAG, rappresentato attraverso quattro caratteri ASCII

L’obiettivo dei Pool TAG è quello di fornire un meccanismo, che attraverso degli identificatore potenzialmente univoci, consenta di stabilire quali driver stanno allocando la memoria. Inoltre, durante la fase di sviluppo di un driver, i TAG sono utili per poter differenziare le diverse tipologie di allocazione, rendendo più selettiva un’eventuale investigazione attraverso il tool Driver Verifier.

Identificare il TAG e byte allocati

Per poter verificare quanti byte sono allocati da un determinato TAG occorrerà utilizzare il tool poolmon.exe, che è possibile recuperare dalla cartella \Support\Tools del CD d’installazione del Sistema Operativo.

Questo tool consente di ottenere un report di tutti i TAG della Paged e Non Paged Pool con i relativi byte allocati.
In Windows Server 2003 il Pool tagging è già abilitato, mentre in Windows Server 2000 e Windows XP è necessario abilitarlo attraverso il tool Gflags.exe presente sempre nella cartella \Support\Tools del supporto di installazione, o modificando le opportune chiavi di registro.

Per maggiori informazioni sull'utilizzo di questo tool potete consultare l’articolo How to use Memory Pool Monitor (Poolmon.exe) to troubleshoot kernel mode memory leaks

La seguente immagine illustra un esempio di output relativo al poolmon:

image008

FIG 1 - Output del tool Poolmon.exe

I campi fondamentali per la nostra analisi sono evidenziati in rosso:

  • Tag : Rappresenta il TAG che identifica l'allocazione.
  • Type : Specifica se la memoria è stata allocata in Paged (Paged) o Nonpaged (Nonp) pool.
  • Bytes : Quantità di memoria allocata, in bytes, per il corrispondente TAG

Possiamo, dunque, utilizzare i seguenti passi per raccogliere l'output del poolmon in una finestra temporale di nostro interesse:

  1. Copiare il file "PoolMon.exe" in "C:\PoolMon", inserendo nella stessa cartella il tool sleep.exe
  2. Aprire una console dei comandi da "Start" --> "All programs" --> "Accessories" --> "Command Prompt"
  3. Spostare il prompt in C:\PoolMon
  4. Per avere una lettura dei dati ogni 15 minuti (per 2 giorni circa), digitare il seguente comando:
    for /l %i in (1,1,200) do ( poolmon -n log-%i.txt && sleep 900000 )
  5. Nella cartella "C:\PoolMon" verranno creati i vari file di log.

Il tool sleep.exe utilizzato è fornito in allegato al presente post.

Determinare la frequenza di campionamento

Sleep.exe richiede un parametro che indica il periodo d'attesa in millisecondi tra due esecuzioni del ciclo for.
Nell’esempio di script riportato sopra, abbiamo il parametro 900’000 che è ottenuto moltiplicando: 15 minuti * 60 secondi * 1000 millisecondi per ottenere una pausa tra una lettura e l’altra di 15 minuti.

Considerando i 200 cicli impostati ogni 15 minuti, abbiamo un campionamento di circa 2 giorni calcolato da: 15 minuti/campione * 200 campioni = 3000 minuti totali / 60 = 50 ore totali / 24 = 2,08 giorni.

Possiamo modificare il numero di cicli e la frequenza di campionamento in base alla rapidità del leak che abbiamo identificato.

Al termine del periodo di monitoring, avremo dunque 200 file di testo, che iniziano con log1.txt fino a  log200.txt nel nostro esempio.

Copiando questi dati in un foglio Excel ed ordinandoli in base al tipo (Nonp o Paged) e in ordine decrescente rispetto ai byte allocati, saremo in grado di determinare la variazione di allocazione dei TAG in funzione del tempo, identificando quali, in particolare, stanno occupando di più.

clip_image006

FIG 2 - Schermata di Excel per l'ordinamento dei TAG.

Analizzare i log

Avremo risultati di questo tipo:

NonPaged Pool

NonPaged - Log 1

NonPaged - Log 10

NonPaged - Log 20

clip_image002 clip_image002[5] clip_image002[7]

Paged Pool

Paged - Log 1

Paged - Log 10

Paged - Log 20

clip_image002[10] clip_image002[12] clip_image002[14]

Come possiamo notare è evidente un notevole incremento del TAG Pipo per la Nonpaged pool.
Analizzando anche i restanti log abbiamo infatti il seguente andamento:

clip_image020

FIG 3 - Andamento della Nonpaged pool allocata dal TAG Pipo.

Come è possibile notare è presente un leak sul TAG Pipo. Ora che abbiamo identificato il TAG che sta alla base del memory leak, come possiamo identificarne il driver corrispondente?

Identificare il driver

L’elenco di tutti i TAG utilizzati per le allocazioni nella memoria Pool sono disponibili nel file
Pooltag.txt Questo file contiene l’identificativo di tutti i componenti Kernel-mode e driver rilasciati con i Sistemi Operativi Windows.

E’ disponibile per il download e l’installazione all’interno dei Debugging Tools for Windows:

Un esempio del contenuto del file Pooltag.txt è riportato di seguito:

 

8042 - i8042prt.sys - PS/2 kb and mouse
AdSv - vmsrvc.sys - Virtual Machines Additions Service
ARPC - atmarpc.sys - ATM ARP Client
ATMU - atmuni.sys - ATM UNI Call Manager
ACPI - acpi.sys - ACPI
Afd? - afd.sys - AFD objects
AfdA - afd.sys - Afd EA buffer

Se il TAG che causa il leak di memoria non è contenuti nell’elenco, vi consiglio di effettuare una ricerca nella nostra Knowledge Base, in modo da verificare la presenza di eventuali problemi conosciuti e installare la relativa hotfix.

Se invece, come nel caso del nostro esempio, il TAG non è Microsoft non sarà presente nell'elenco.
In questo caso possiamo utilizzare il comando findstr, valido per ciascuna versione di Windows, che potrà essere eseguito come indicato di seguito:

  • Aprire una console dei comandi da "Start" --> "All programs" --> "Accessories" --> "Command Prompt"
  • Spostarsi nella cartella %systemroot%\system32\drivers
  • Digitare il comando
    findstr /m /l <tag> *.sys
  • Verificare l'output restituito dal comando

In questo screenshot è evidenziata la ricerca per il TAG Pipo:

clip_image022

Come possiamo notare è restituito il driver corrispondente al TAG specificato “Pipo”.

In questo caso occorrerà verificare un'eventuale versione aggiornata del driver Pippo.sys, o eventualmente contattare il fornitore del software segnalando la problematica.

Conclusione

Alla luce di quanto visto fino ad ora, se stiamo evidenziando un leak di memoria sul nostro sistema potremo identificarne la potenziale causa attraverso i seguenti passi:

  • Monitorare i byte allocati da ciascun TAG durante una finestra temporale adeguata al nostro leak, attraverso il tool poolmon.exe
  • Evidenziare eventuali allocazioni che variano proporzionalmente al tempo in costante crescita
  • Stabilire su che tipo di pool è presente il leak (Paged o Nonpaged)
  • Stabilire il driver associato al TAG che sta causando il leak
  • Ricercare eventuali problemi noti, o analizzare la problematica con il fornitore del driver

Mattia Tocco
Senior Support Engineer
Microsoft Enterprise Platform Support

Sleep.exe.rimuovi