Introduzione

Alcuni problemi riportati da applicazioni server, come anche da applicativi tradizionali, possono essere ricondotti all'esaurimento di memoria. Una domanda che spesso ci si pone è se si possa risolvere il problema aumentando la disponibilità di memoria RAM (Random Access Memory), ovvero la memoria fisica installata sul server o sulla workstation. In taluni casi la risposta è affermativa ma sfortunatamente in molte altre situazioni un upgrade hardware non risolve il problema.

Un errore riportato come un esaurimento di memoria o di risorse può essere riferito ad un particolare tipo di memoria, con certi limiti, i quali non sono correlati alla quantità di memoria totale installata sulla macchina ma primariamente legati all'architettura del processore e a come è stato progettato il sistema operativo.

In questo post vengono analizzate e classificate le principali risorse di memoria gestite dal sistema operativo, sono poi considerati gli scenari generici di esaurimento per i vari casi trattati. In un seguente post si vedranno i principali parametri da verificare ed un cenno alle metodologie di troubleshooting. Poiché la piattaforma a 32 bit è più soggetta a problemi di esaurimento di risorse, per le evidenti limitazioni rispetto a quella a 64 bit, essa sarà l'oggetto primario del post. Le informazioni architetturali trattate sono comunque valide per ogni sistema Windows e salvo casi particolari applicabili anche alla seconda. Ove si quantifichino dei valori numerici sono invece da considerarsi specifici alla piattaforma a 32 bit.

I contenuti dei primi post su questa tematica saranno primariamente teorici ed architetturali, introduttivi a quelli che seguiranno da parte mia e dei miei colleghi, indirizzati alla risoluzione di problemi più specifici.

Classificazione delle risorse di memoria nel sistema operativo Microsoft Windows

  • Memoria fisica: con questo termine si intende la memoria RAM installata e presente sul server, si tratta quindi di hardware effettivamente nella macchina. Nelle modalità di esecuzione dei processori nei moderni sistemi operativi (paging abilitato) la memoria fisica non è direttamente accessibile: è sempre necessario un meccanismo di mapping che permetta di indirizzare la memoria virtuale o logica (definita sotto) su quella fisica. I recenti processori Intel a 32 bit supportano un massimo di 64GB di memoria, limitata a questi valori dall'architettura. Quelli a 64 bit ne supportano quantità maggiori e crescenti in futuro.
  • Memoria virtuale o spazio di indirizzi logico: tramite il mapping citato sopra vengono presentati 4GB di memoria virtuale al codice che gira sul processore. Tale memoria virtuale può mapparsi sulla memoria fisica, su pagine di memoria riversate sul disco (paging file) o su nessuna destinazione per intervalli di indirizzi virtuali non in uso.
    Relativamente a questo argomento i termini logico e virtuale sono intercambiabili, più precisamente il primo è parte della terminologia definita da Intel per i propri processori, il secondo è più legato all'ambito dei sistemi operativi, come per esempio Windows, che è stato progettato per essere portabile su differenti architetture, quindi non legato alle terminologie specifiche di particolari tipi di hardware.
  • Risorse kernel: il kernel del sistema operativo alloca memoria, per le proprie funzioni e per i driver installati da tre importanti risorse, inaccessibili agli applicativi: due pool (nonpaged e paged) e le System PTE. Il fatto che ci siano tre risorse diverse è per soddisfare certi differenti requisiti, che rendono alcune risorse più preziose di altre, in dettaglio:
    • Non-paged pool: la caratteristica di quest'area di memoria per le allocazioni del kernel è di essere sempre disponibile e permanentemente mappata su memoria fisica, in altre parole non può essere paginata sul disco di paging, da cui il nome. Date queste sue caratteristiche è più preziosa delle altre due, richiedendo costantemente una quantità di memoria fisica pari alla sua dimensione.
    • Paged pool: è un'altra forma di memoria allocabile dai componenti kernel, è meno pregiata, quindi generalmente più abbondante, in quanto all'occorrenza può essere oggetto di paging (swap) per liberare memoria fisica ad altre esigenze.
    • System PTE: sono degli elementi di allocazione con granularità di una pagina di memoria (4096 byte) ed hanno particolari caratteristiche che le rendono più versatili delle precedenti. Possono essere usate solo per specifici scopi da parte di pochi componenti del kernel, data la complessità di gestione, che è il prezzo della loro versatilità. A titolo di esempio gli stack kernel, i memory mapped device, alcuni tipi di video buffer e i buffer di memoria per trasferimenti di tipo DMA (Direct Memory Access) utilizzano questa risorsa.

Per ciascuna delle risorse citate un consumo eccessivo ed incontrollato può sempre portare all'esaurimento, più frequentemente uno o più componenti possono allocare memoria dei vari tipi e non rilasciarla, tipicamente per un bug, anche in questo caso se non interviene un reboot si arriva più o meno velocemente all'esaurimento. Questo tipo di esaurimento è definito come memory leak.

Aspetti specifici per ciascuna categoria e tipologie di esaurimento

  • Memoria fisica: sebbene la prima ipotesi a cui si vorrebbe attribuire un esaurimento di memoria sia quasi sempre la memoria fisica, nella realtà gli esaurimenti di questa risorsa sono rari. Il sistema operativo gestisce molto bene la memoria fisica. Potendosi poggiare sul paging file per liberare memoria, è difficile che si arrivi realmente al punto di non averne a sufficienza per le funzioni minime di un server. In realtà la penuria di questa risorsa viene percepita molto presto come un peggioramento progressivo della performance del server che, trovandosi a dover continuamente spostare dati tra memoria fisica ed il file di paging, allo scopo appena citato, diventa molto lento.
    In ogni caso, quando si arrivi alla conclusione che un server necessita di 4GB o più, si rende necessario abilitare un kernel alternativo del sistema operativo che sfrutta su una funzionalità del processore denominata PAE (Physical Addressing Extension). Tramite questo meccanismo i 32 bit di indirizzi logici vengono mappati su 36 bit permettendo di indirizzare, e quindi installare, fino a 64GB di memoria fisica. L'abilitazione di questo meccanismo avviene tramite lo switch /PAE nel boot.ini. Questo switch non ha nessuna relazione con il /3GB, descritto sotto e che agisce sugli spazi di indirizzamento logici.
    E' da notare che anche con soli 4GB il PAE è necessario per vedere tutta la memoria presente, a causa di un intervallo di indirizzi fisici aggiuntivi occupati da certi dispositivi hardware (es. PCI devices).
  • Memoria virtuale o spazio di indirizzi logico: Questo spazio, di 4GB per le architetture a 32 bit, è diviso in due parti che vanno rispettivamente al kernel e agli applicativi, La seconda porzione, per gli applicativi, è strutturata in modo che ognuno ne abbia una sua visione privata, che è alla base della garanzia del loro isolamento. La divisione di default, sin dal design iniziale del sistema operativo Windows NT 3.1, è di 2GB per il kernel e 2GB per lo spazio lasciato agli applicativi.
    Il sistema deve ripartire lo spazio kernel, di 2GB, tra le tre risorse del kernel descritte sopra. Questa divisione avviene in modo più o meno statico, a seconda della versione del sistema, e non si arriva mai ad esaurire lo spazio di indirizzi in quanto tale, tuttavia, data la ripartizione appena citata, quello che può succedere è che si esauriscano le singole risorse, i tre casi vengono quindi analizzati oltre.
    A livello applicativo, specie per applicazioni server (es. Microsoft SQL Server, Microsoft Exchange Server) il massimo di 2GB può essere effettivamente limitante. Per aumentare questa risorsa agli applicativi già da Windows NT4.0 venne introdotto lo switch del boot.ini /3GB. Questa impostazione alternativa permette di offrire 3GB di spazi di indirizzi virtuali agli applicativi, tuttavia questo avviene a scalpito degli spazi kernel che devono limitarsi a 1GB e questa riduzione impatta significativamente le tre risorse kernel, che risultano notevolmente limitate, a grandi linee dimezzate.
    Sia nella configurazione tradizionale che /3GB un eventuale esaurimento dello spazio a disposizione degli applicativi potrebbe essere percepito con errori tipo "Out of memory", "Not enough resources" o similari. In questo caso solo l'intervento di supporto di chi ha venduto o sviluppato il software può identificare con precisione se effettivamente si è arrivati a questo esaurimento.
    Tecniche che gli sviluppatori hanno a disposizione per poter gestire dati di grandi dimensioni su piattaforme a 32 bit sono AWE (Address Windowing Extension) e l'attivazione di un particolare bit nell'immagine del proprio eseguibile, IMAGE_FILE_LARGE_ADDRESS_AWARE, per essere effettivamente abilitati all'accesso di tutti i 3GB nella configurazione /3GB. I dettagli su queste due tecniche esulano dallo scopo di questo post. Su piattaforma a 64 bit gli applicativi a 64 bit hanno a disposizione un vastissimo spazio di indirizzo che non viene correntemente considerato limitante in alcun modo. Un applicativo a 32 bit, con il bit IMAGE_FILE_LARGE_ADDRESS_AWARE attivo, accede a 4GB su una piattaforma a 64 bit, traendo quindi un certo vantaggio.
    E' importante ribadire che tutto quanto descritto in questo paragrafo avviene in termini di spazi di indirizzi virtuali, quindi in modo pressoché indipendente dal numero di GB di memoria fisica disponibile sul server.
  • Non-paged e paged pool: l'esaurimento di una delle pool o entrambe causa seri problemi di stabilità. Tutti i componenti kernel del sistema ed i driver non riescono ad allocare memoria anche per semplici operazioni di base. In teoria al permanere di questa penuria il server diventa incapace di svolgere numerose funzioni, il che impedisce di erogare i servizi per il quale è preposto. Nella pratica in numerosi casi si arriva al blue screen o al blocco irreversibile del server, infatti la continuata incapacità di svolgere i propri compiti colpirà prima o poi una funzione vitale del server che può manifestarsi nei modi citati, altresì certi driver non sono perfettamente testati nel gestire queste situazioni limite e quindi espongono dei bug, che normalmente non si vedrebbero, e che possono portare al blue screen.
    Nella maggioranza dei casi l'esaurimento delle pool è dovuto a memory leak nei driver o in certi componenti del sistema operativo. In altri casi le applicazioni, sebbene non abbiano accesso diretto per allocare da questa risorsa, posso ugualmente indurre il loro esaurimento. Ciò avviene se richiedono funzioni che nella loro implementazione, nel kernel, alloca dalle pool. Ad esempio un applicativo che aprisse numerosi file o connessioni di rete senza mai chiuderli causerebbe un memory leak, in questo esempio primariamente nella paged pool.
    Un server con una configurazione particolarmente complessa, che include molti componenti kernel diversi, quando sotto carico potrebbe arrivare ad esaurire una delle pool, pur non avendo alcun memory leak.
    Un dimensionamento non appropriato delle pool, nei valori del Memory Manager (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management) nel registry, può portare al loro esaurimento in quanto semplicemente insufficienti.
  • System PTE: l'esaurimento delle System PTE porta a fenomeni simili a quelli descritti sopra, in questo caso i componenti che allocano questa risorsa sono più interni al sistema e quindi si hanno effetti, dal punto di vista interno al sistema, differenti ma con sintomi paragonabili a quelli appena descritti. Spesso la penuria di System PTE (meno di 3000-5000 PTE libere) porta ad un errore di inizializzazione degli applicativi con codice 0xC0000142 (STATUS_DLL_INIT_FAILED).
    Anche in questo caso la maggioranza degli esaurimenti viene identificata in leak su questo tipo di risorsa per mancati rilasci in driver o componenti kernel, l'esempio più classico è il mancato rilascio di buffer di I/O allocati per trasferimenti DMA.
    Bug negli applicativi non sono solitamente correlabili a System PTE leak.
    Un dimensionamento non appropriato delle System PTE, nei valori del Memory Manager nel registry (valore "SystemPages"), può portare al loro esaurimento in quanto semplicemente insufficienti.

Conclusione

Questo post ha voluto trattare una classificazione delle risorse comunemente denominate come "risorse di memoria" e gli scenari che possono dar luogo a dei problemi. Costituisce una base teorica per dei post più pratici e rivolti alla risoluzione di problemi reali che verranno trattati in futuro su questo blog.

Fabio Lavatelli
Escalation Engineer
Microsoft Enterprise Platform Support