posts - 644, comments - 2675, trackbacks - 143

My Links

News

Raffaele Rialdi website

Su questo sito si trovano i miei articoli, esempi, snippet, tools, etc.

Archives

Post Categories

Image Galleries

Blogs

Links

Memoria e GC parte 1: Task Manager e Mem Usage

A quanto sembra nell'ultimo Workshop c'è stato molto interesse sulla parte in cui parlavo di memoria. Allora ho pensato di riscrivere nel blog alcuni di quei concetti e magari di espanderne altri per cui non c'è stato il tempo.

In ogni post, se necessario, anticiperò qualche definizione... lungi da me darne una versione enciclopedica, per quelle ci sono libri mastri quali "Windows Internals" di Solomon-Russinovich e "Advanced Windows" di Richter a cui rimando per ogni approfondimento. Lo scopo di queste definizioni è solo per non perdere il filo del discorso da parte di chi non è familiare con questi termini.

  • In Windows ogni processo definisce uno spazio di indirizzamento virtuale al di fuori del quale il codice non può andare a scrivere. Vale a dire che un puntatore, per quanto bizzarro valore possa assumere non potrà uscire da questo spazio di indirizzamento, e quindi non sovrascrivere la memoria di altri processi a meno che il processo non condivida delle pagine di memoria con altri.
  • Lo spazio di indirizzamento dipende dall'architettura della CPU e nel caso di 32bit è 2^32 cioè 4GB di Ram indirizzabile da ogni processo. Questo spazio è normalmente diviso in due parti 2GB in User mode (la porzione dove vengono caricate le applicazioni) e 2GB in Kernel mode (dove gira il sistema operativo, i driver, etc.). Esiste un opzione del boot.ini per cui la divisione può essere di 3GB in User mode e 1GB in Kernel mode
  • Ogni processo ha associato almeno un thread. Il thread è l'unità di esecuzione senza il quale il codice non può eseguire codice. Lo scheduler di Windows è preposto a decidere quanto tempo dare a ciascun thread del sistema in modo che l'esecuzione di tutti i processi sia il più omogenea possibile, in relazione anche alle priorità assegnate ai thread.
  • Cos'è il rebasing? Ogni volta che un processo carica un modulo in memoria cerca di caricarlo all'indirizzo specificato dal developer. Quando l'indirizzo di memoria è già occupato, Windows deve rilocare (ribasare) la DLL in memoria aggiustando naturalmente tutti gli indirizzi di memoria della DLL. I problemi del rebasing sono molteplici e se interessa, dedicherò un post a questo argomento.
  • Cos'è il paging su disco? Per far fronte alla necessità di memoria di tutti i processi, Windows ogni tanto scarica alcune pagine in RAM su disco, permettendo ad altri processi di usare RAM. Tipicamente più è usata la RAM fisica e migliore è la performance generale del sistema.
  • Cosa sono i page fault? Quando un processo richiede della memoria e questa non è subito disponibile, viene scatenato un page fault. Se la pagina in questione è nel file di paging su disco fisso, il page fault è detto "hard page fault". Maggiori sono gli "hard page fault" e minore è la performance generale del sistema. I "soft page fault" sono invece generati se la pagina non è stata trovata ma è già in memoria e tipicamente non sono responsabili di grosse perdite di performance. 

Veniamo ora alla memoria...
Perché ci dobbiamo preoccupare dell'occupazione di memoria? La domanda sembra scontata ma in fondo per ogni domanda, anche scontata, ci devono essere motivazioni oggettive.

  • Perché la RAM è una risorsa relativamente limitata e ha un costo abbastanza alto rapportato all'uso che attualmente ne facciamo
  • Perché la mancanza di RAM abbatte le performance del PC
  • Perché nelle architetture a 32bit la memoria per ogni processo ha un limite che si può raggiungere senza troppa difficoltà

A questo punto diventa necessario misurare l'occupazione di memoria della nostra applicazione. Dimentichiamoci per il momento che l'applicazione sia managed, ossia che usi il Framework.NET. Parliamo generalmente di processi.

Lo strumento più usato è il task manager e la colonna che per default mostra un valore di memoria è "Mem Usage". Il corrispettivo valore in Process Explorer è "Working Set".

  • Cosa rappresenta "Mem Usage"?
    È il "working set" cioè la somma di pagine di memoria private + pagine che il processo condivide con altri processi. Sono tutte pagine in RAM fisica, cioè non su disco.
  • Perché "Mem Usage" non è un'informazione utile?
    Le pagine di memoria condivise sono contate per ciascun processo. Per cui la somma di tutti i "Mem Usage" di tutti i processi è superiore alla memoria realmente occupata.
  • Quando accade che un processo condivida le sue pagine?
    Ad esempio la porzione read-only delle DLL che vengono caricate in un processo e non sono ribasate dal loader vengono condivise, permettendo al sistema di occupare meno memoria.

Considerato che esistono sempre più applicazioni managed e che quindi è sempre più probabile che su un PC ce ne sia una attiva, certamente le System.*.dll saranno condivise tra tutti i processi managed. Lo stesso vale per le dll delle "C Runtime Library", delle MFC, ATL, VB e ovviamente quelle di sistema.

Detto questo, una applicazione managed che ha un alto "Mem Usage" potrebbe anche significare che usa pochissima memoria e fa un alto uso di DLL già in uso da altri processi.
Essendo una somma, l'analisi di solo questo valore è insufficiente a trarre risultati, ma se nel sistema sono presenti altre applicazioni managed, l'occupazione delle dll del Framework.net va suddiviso tra tutte queste.

Ovviamente esistono altri sistemi per avere informazioni più precise, e saranno oggetto dei prossimi post.

Print | posted on venerdì 20 aprile 2007 9.28 |

Feedback

Gravatar

# re: Memoria e GC parte 1: Task Manager e Mem Usage

veramente ottimo, complimenti!
20/04/2007 13.49 | Luciano Castro
Gravatar

# re: Memoria e GC parte 1: Task Manager e Mem Usage

Molto interessante Raffaele, ti faccio i complimenti e aspetto le prossime puntate... ciao!
20/04/2007 14.05 | Federico
Gravatar

# Re: Memoria e GC parte 1: Task Manager e Mem Usage

thx Raf...
questi post staranno nell mia hall of fame ;-)
saluti
20/04/2007 14.26 | Roberto Messora
Gravatar

# re: Memoria e GC parte 1: Task Manager e Mem Usage

E' possibile anche con codice Managed usare la colonna "Private Bytes"? Purtroppo programmando in C++ non managed, capita spesso di dover andare a cercare memory leak e quindi utilizzare la sola informazione Private Bytes.
Mi chiedevo, con C++/CLI e codice misto come si cercano i Memory Leak della parte non managed? Non si rischi di pensare a dei leak quando è semplicemente la parte managed a richiedere memoria.
CIAO
20/04/2007 22.58 | FabioP
Gravatar

# re: Memoria e GC parte 1: Task Manager e Mem Usage

Ciao Fabio, il valore ha sicuramente senso perché è del processo.
In questi post la mia intenzione è di iniziare prima a partire dai concetti che sono validi per tutti i processi per poi scendere nel dettaglio del GC.

In senso stretto un leak di memoria managed è semplicemente un reference attivo (una root) verso una allocazione managed. Questo genere di cose si vedono meglio con CLRProfiler di Microsoft e in alcuni casi meglio con un Memory Profiler come Ants di Red Gate o quello presente nelle versioni Team Suite di Visual Studio.

Se invece intendi un leak di memoria nativa, va ricercato come sempre si è fatto. Dal punto di vista nativo il CLR è semplicemente un componente COM che lavora in modo concorrente nel tuo processo.
I tool più indicati per i leak in memoria nativa sono il LeakDiag di Microsoft oppure BoundsChecker di Compuware.
21/04/2007 1.03 | Raffaele Rialdi
Gravatar

# re: Memoria e GC parte 1: Task Manager e Mem Usage

Grazie a tutti per i feedback ... ho già postato la seconda parte e spero che sia interessante per tutti.
A presto per la terza ...
23/04/2007 19.03 | Raffaele Rialdi
Gravatar

# Imparare Microsoft Visual C++ 6.0 - Pagina 7 | hilpers

Imparare Microsoft Visual C++ 6.0 - Pagina 7 | hilpers
21/01/2009 17.08 | Pingback/TrackBack

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 8 and 8 and type the answer here:

Powered by: