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:
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:
- Copiare il file "PoolMon.exe" in "C:\PoolMon", inserendo nella stessa cartella il tool sleep.exe
- Aprire una console dei comandi da "Start" --> "All programs" --> "Accessories" --> "Command Prompt"
- Spostare il prompt in C:\PoolMon
- 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 ) - 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ù.
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 |
Paged Pool
Paged - Log 1 |
Paged - Log 10 |
Paged - Log 20 |
Come possiamo notare è evidente un notevole incremento del TAG Pipo per la Nonpaged pool.
Analizzando anche i restanti log abbiamo infatti il seguente andamento:
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:
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
Comments
Anonymous
January 01, 2003
Abbiamo ricevuto una richiesta di maggiori informazioni riguardo a come risolvere identificati sul tag IRP. Le IRP, I/O Request Packet, sono allocate con il tag "IRP " e rappresentano richieste di I/O da parte di applicativi, servizi o driver nel sistema. L'aumento della memoria associata a questo tag è indicativa del fatto che viene richiesto più I/O di quanto ne stia venendo scodato. Ci sono sostanzialmente due possibili scenari: -) Un dispositivo di I/O è bloccato, tipicamente uno storage device, e quindi verso tale dispositivo nulla viene scodato. Siccome gli applicativi continuano a generare I/O si arriva prima o poi all'esauriumento della memoria. -) Gli applicativi generano mediamente più I/O di quanto ne possa scodare lo storage. E' più raro che si possa arrivare a questo scenario fino al punto di esaurire tutta la memoria. Per diagnosticare e risolvere questo problema si possono usare in modo incrociato alcune tecniche quali: -) Dump forzato della macchina nello stato di alto utilizzo per distinguere quale dei due casi sia. -) Monitoring dell'I/O sui dischi fisici tramite performance monitor per verificare il traffico al manifestarsi del problema. Tale monitoring sarebbe da incrociare con i counter "memory" per correlare la crescita dell'uso della pool con il precedente. -) Aggiornamento generico dei driver associati allo storage. Verifica/analisi della domanda di I/O degli applicativi confrontata con la banda teoricamente disponibile verso lo storage. Saluti. Filippo CerutiAnonymous
January 01, 2003
Ciao Luciano, nel file pooltag.txt sono inseriti i tag utilizzati dai principali driver del sistema operativo. Molti driver di terze parti utilizzano dei tag personalizzati. Nel tuo caso abbiamo: File - utilizzato dai "File objects" IoNm - utilizzato dalle funzioni "nt!io" per "Io parsing names" CcPc - utilizzato dalle funzioni "nt!cc" per "Cache Manager Private Cache Map" Per eseguire la ricerca dei tag all'interno dei driver, puoi seguire questo articolo pubblico: KB 298102 How to find pool tags that are used by third-party drivers http://support.microsoft.com/kb/298102 Una volta identificato i driver che causano il problema, puoi cercare se esiste una versione aggiornata. I tag sono tutti riconducibili a handle aperti su file, quindi consiglierei di verificare con il perfmon il counter Handle dei Processi e vedere quale processo tiene aperti molti file. Alcuni antivirus hanno problemi noti e non chiudono correttamente gli handle ai file, quindi verifica di avere gli ultimi aggiornamenti installati. Grazie e Buona giornata. Daniele MasoAnonymous
January 01, 2003
Ciao Luciano, continuerei sulla strada del perfmon per identificare il processo che consuma memoria e tiene file aperti. Una prova empirica per verificare se aumenta il totale, consiste nel disabilitare momentaneamente il software antivirus che generalmente causa questo tipo di problemi. Per quanto riguarda la configurazione del perfmon, procedi così: -) Avvia perfmon -) Aggiungi i seguenti counters: ---> Process Handle Count ---> All Instances -) Pulsante ADD Puoi eseguire una registrazione dei counter per 1 settimana fino al blocco del server in modo da poter analizzare lo storico. Oppure, se sei già vicino al blocco, procederei all'analisi "live" dei valori. Considera che in generale System ha orientativamente un numero di handle elevato che puoi confrontare con altri processi (inizia da quelli non Microsoft) che possono avere il problema. Grazie e Buona giornata. Daniele MasoAnonymous
October 28, 2009
Complimenti per l'articolo, chiaro e esauriente. Ho un problema di memory leak su un server con W2003 Enterprise SP2 con l' opzioni nel boot.ini /noexecute=optout /fastdetect /redirect /pae /3gb Il server era arrivato a bloccarsi ogni 7 giorni, grazie ai tuoi articoli, analizzando i TAG ho individuato un driver dell'antivirus che aumentava costantemente. Disinstallato l'antivirus l, sono risucito a prolungare la 'vita' del server a più di un mese. Ma il problema persiste ancora, tenendo sotto controllo i TAG , ho verificato che esistono ancora alcuni TAG che crescono costantemente : File, IoNm e CcPc, raggiungendo valori alti. Nel file pooltag.txt non trovo riferimenti a driver *.sys specifi. Nel tuo articolo suggerisci di cercare nella Knowledge Base, ma non ho trovato niente. Puoi indicarmi il modo o la Knowledge Base specifica dove cercare i riferimenti a questi TAG , per individuare i driver responsabili ? Grazie Luciano Picchioni GE Transportation System SpaAnonymous
November 25, 2009
Grazie per la cortese risposta. Ho provato a seguire i suoi consigli ma non sono riuscito a individuare i driver .sys che potrebbero causare il blocco del server. Analizzando ogni giorno l'andamento del consumo di memoria dei TAG con il comando POOLMON si evidenzia come i TAG File,CcPc e IoNm presentano valori sempre in crescita. Ho effettuato anche il controllo sul totale dell'occupazione di memoria suddivisa in NONPAGED e PAGED. Ho verificato che mentre il totale della PAGED rimane pressochè stabile quello della NONPAGED è in crescita costante. Quindi ho concentrato la mia attenzione sui TAG NonPaged ( File , CcPc ). Ma , come ho già accennato non riesco a trovare i *.sys corrispondenti. Con il comando FINDSTR ottengo i seguenti risultati : C:>findstr /m /l hFile *.sys C:>findstr /m /s /l hFile *.sys WINDOWSServicePackFilesi386dot4.sys WINDOWSServicePackFilesi386nfssvr.sys WINDOWSServicePackFilesservicepackcachecmpnentsr2nfssvr.sys WINDOWSServicePackFilesservicepackcachei386nfssvr.sys C:>findstr /m /s /l hCcPc *.sys C:>findstr /m /s /l CcPc *.sys C:> In pratica la ricerca per il TAG CcPc su tutte le sottodirectory in C non da risultato mentre per il TAG File , con l'opzione hFile trovo alcuni file , ma non in directory utilizzate da l sistema operativo. Ho tentato di utilizzare PERFMON per verificare quali sono i processi che tengono tanti handle aperti, come mi ha suggerito, purtroppo ci sono troppe opzioni in perfmon e non sono risucito a capire qual'è il settaggio giusto per attivare il monitoring. Potrebbe indicarmi qualche documento che possa aiutarmi nella configurazione di perfmon nel mio caso? Grazie Luciano Picchioni