Salve a tutti e bentornati.

Oggi parliamo di una cosa molto molto importante. Sconosciuta ai più semplicemente perchè stiamo parlando di una cosa che riguarda i limiti del sistema operativo stesso. Avere a che fare con un problema di Desktop Heap, significa essersi avvicinati ai limiti fisici del sistema operativo, e la cosa non dovrebbe mai accadere in circostanze normali.

Innanzitutto due link fondamentali:

Introduzione al Desktop Heap
http://blogs.msdn.com/ntdebugging/archive/2007/01/04/desktop-heap-overview.aspx

DHeapMon, tool per misurare l’utilizzo dei vari heap
http://www.microsoft.com/downloads/details.aspx?familyid=5CFC9B74-97AA-4510-B4B9-B2DC98C8ED8B&displaylang=en

 

Il seguente articolo invece è l’unico articolo pubblico della Knowledge Base che spiega i misteriosi parametri del valore SharedSection:

184802  User32.dll or Kernel32.dll fails to initialize
http://support.microsoft.com/default.aspx?scid=kb;EN-US;184802

 

Leggendo attentamente il primo articolo, scopriamo che le Sessioni possono contenere una o più Window Station e che ogni Window Station può contenere uno o più Desktop. Solo una Windows Station per sessione può interagire con l’utente, e questa di solito è quella di Default, chiamata “Winsta0”. La Window Station contiene una Clipboard, una serie di Global Atom e un gruppo di oggetti Desktop. Ogni Desktop ha un display logico e contiene Windows, Menu e Hooks.

Ogni Desktop possiede un Desktop Heap.

Lo spazio totale dedicato dal sistema operativo al Desktop Heap è gestito attraverso il parametro SessionViewSize nella chiave di registry

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management

Nei sistemi operativi recenti, questo valore è ridimensionabile e di default già abbastanza grande, rispetto al passato. Ad esempio, in Windows 2003 questo valore è 30 esadecimale che significa 48 in decimale, quindi 48 MB, quando una volta su XP era 20MB. Nei sistemi operativi a 64 bit si parte da 100MB ormai.

 

Configurare la dimensione di ciascun Desktop Heap.

La dimensione di ciascun Desktop Heap è configurabile attraverso il valore SharedSection della seguente chiave:

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SubSystems\Windows

Generalmente il valore di default per questa chiave è qualcosa del genere:

%SystemRoot%\system32\csrss.exe ObjectDirectory=\Windows SharedSection=1024,3072,512 Windows=On SubSystemType=Windows ServerDll=basesrv,1 ServerDll=winsrv:UserServerDllInitialization,3 ServerDll=winsrv:ConServerDllInitialization,2 ProfileControl=Off MaxRequestThreads=16

Come vedete la voce SharedSection contiene 3 valori espressi in KB di memoria:

1024 indica la dimensione di Shared Heap comune a tutti i desktop e che non deve mai essere modificato.

3072 indica la dimensione del Desktop Heap allocato per ogni desktop associato con la Window Station interattiva, con l’eccezione dei desktops “Disconnect” e “Winlogon” che hanno una dimensione fissa di 64K e di 128K.

512 indica la dimensione di ciascun Desktop Heap associato con una Window Station non interattiva, tipicamente quella di un servizio.

 

Ci possono essere solo due tipi di esaurimento del Desktop Heap:

  1. Esaurimento del Session View space a causa della creazione di un numero elevato di desktops nella Sessione/WindowStation
  2. Un singolo specifico desktop che si riempie fino all’esaurimento; un desktop interattivo che si riempie completamente a causa di una singola applicazione (o un piccolo numero di applicazioni) che allocano un gran numero di oggetti GDI o User, o un desktop dei servizi che si riempie a causa dell’elevato numero di servizi che viene avviato con quell’account.

 

La matematica intorno al Desktop Heap.

Gli unici valori interessanti sono quindi il secondo, 3072, e il terzo, 512.

Il secondo valore indica che per ogni desktop creato nella Winsta0, le applicazioni eseguite, condivideranno questi 3Mb. Quindi se avete una applicazione che crea tanti window handle o thread handle, nonchè oggetti GDI o User, e che quindi consuma tanta percentuale di questo spazio, potreste trovarvi al limite anche eseguendo solo poche applicazioni. Allo stesso modo, se avete applicazioni che durante l’esecuzione, si creano dei desktop paralleli, risulterà che verranno allocate tante sezioni da 3MB per ogni nuovo desktop creato. Tutti questi desktop, più quelli creati dai servizi, non possono occupare più di 48MB.

Quindi, se vogliamo modificare questo valore, perchè vogliamo poter eseguire più applicazioni contemporanemante, possiamo aumentare questo numero da 3072 fino a 12288 (che è il valore di default di Windows Vista ad esempio) senza troppi problemi. Se lo incrementiamo ancora di più dobbiamo essere sicuri che non usiamo applicazioni che creano desktop alternativi (usando l’API CreateDesktop), perchè ogni nuovo desktop a quel punto rischierà di esaurire la SessionViewSize.

I servizi hanno regole tutte loro. Col fatto che non sono interattivi (e adesso sono anche isolati), 512KB bastano di solito per ogni “account”. Perchè dico questo: perchè lo SCM (il Service Control Manager) ha delle regole legate al token di sicurezza dell’account usato per avviare il servizio. Quindi, per ogni account usato per avviare un servizio, viene creato un Desktop non interattivo.

Tutti i servizi avviati come Local System condivideranno 512KB, tutti quelli avviati come Network Service altri 512KB, così come altri 512KB verranno assegnati a Local Service e ad ogni altro servizio configurato per girare con un account specifico, locale o di dominio. Ecco che allora risulta chiara la correlazione tra la SessionViewSize e i parametri della SharedSection.

 

Facciamo un pò di esempi.

Supponiamo di avere un servizio che viene avviato con un acount locale, due con un account di rete, un altro con un altro account di rete e i soliti dei servizi standard. Praticamente avremo 6 account diversi usati in totale, che quindi causeranno la creazione di 6 desktop diversi, per un totale di, 6 x 512Kb, 3MB.

Se avessimo 100 servizi avviati tutti come Local System, questi 100 servizi condividerebbero gli stessi 512KB di memoria. Se questi servizi non usassero in alcun modo funzioni da user32.dll, non ci sarebbe problema, in caso contrario se questi usassero tutti 50K di spazio, 512KB sarebbero pochi, e la soluzione sarebbe quella di aumentare il secondo valore di SharedSection, così da accomodare l’esecuzione dei 100 servizi.

Se avessimo 100 servizi ognuno avviato con un account diverso, avremmo la creazione di 100 desktop non interattivi diversi e quindi qualora avessimo aumentato il valore 512KB esauriremmo la SessionViewSize più velocemente, quindi nel caso avessimo 100 servizi da avviare tutti con un account diverso, dovremmo ridurre il secondo parametro, altrimenti, 100 x 512Kb = 50 MB, che è maggiore di 48MB. In questo caso, si procede per tentativi, diminuendo ogni volta di 64KB il parametro, fino a trovare la dimensione che soddisfa i nostri requisiti.

Ovviamente, nel calcolo bisogna tenere presente anche la parte che riguarda la sessione interattiva, come abbiamo visto prima.

Quindi, a grandi linee, una formula per calcolare le varie dimensioni potrebbe essere questa:

SessionViewSize >= (Numero di Desktop interattivi in Winsta0 * secondo parametro) + (Numero di desktop non interattivi * terzo parametro)

I valori di default sono abbastanza bassi da consentire la creazione di diversi desktop sia interattivi che non interattivi.

Ma facciamo un paio di esempi pratici, riferiti a Vista, così sappiamo che il valore SharedSection vale SharedSection=1024,12288,512 e SessionViewSize è 48MB

Supponiamo di avere 8 servizi che vengono avviati con 8 account diversi, più i 3 account normali. Tra le applicazioni ne abbiamo 1 che crea un altro desktop.

Per la formula sopra, avremo che

48 >= (2*12.288) + (11*0.512)

Che è vero, perchè 24MB+5.6 è minore di 48 e quindi non avremo problemi.

Supponiamo però adesso di dover eseguire dei servizi aggiuntivi tale per cui avremo 50 servizi tutti eseguiti con un account diverso. A questo punto avremo che 48MB non è più maggiore di 24.4MB + 25.6MB e quindi saremo a corto di Desktop Heap. In questo caso,per risolvere il problema, visto che non abbiamo esigenze particolari per le applicazioni user mode, potremmo ridurre il secondo valore da 12288 a 8000 ad esempio, e il nostro problema sarà risolto.

 

C’è purtroppo un altro fattore che entra in gioco spesso: i Terminal Services. SessionViewSize abbiamo detto che sui sistemi operativi moderni è di default 48MB.

Quando però abilitiamo i Terminal Services (che ricordo sono presenti anche in XP quando è abilitato il FUS, Fast User Switching), la SessionViewSize viene ridotta a 20MB, quindi capite che a questo punto il Desktop Heap diventa una risorsa importante e può essere fondamentale capire come viene utilizzata.

 

Come misurare l’utilizzo del Desktop Heap.

Con DheapMon.
Scaricate il Desktop Hea Monitor da qui: http://www.microsoft.com/downloads/details.aspx?familyid=5CFC9B74-97AA-4510-B4B9-B2DC98C8ED8B&displaylang=en

Seguite le istruzioni per l’installazione contenute nel Readme.htm e in Dheapmon.chm.

Funziona anche su Vista e 2008. Le istruzioni per il setup su questa piattaforma sono queste:

C:\kktools\dheapmon8.1\x86>dheapinst.exe -y srv*http://msdl.microsoft.com/download/symbols
C:\kktools\dheapmon8.1\x86>dheapmon -l
C:\kktools\dheapmon8.1\x86>dheapmon -p -a -f dheap.txt
C:\kktools\dheapmon8.1\x86>dheapmon -u
C:\kktools\dheapmon8.1\x86>dheapinst -r

Dheap.txt conterrà l’output del tool. Quello che segue è un log di un Windows Server 2003 Sp2.

Potete notare i tre desktop in Winsta0, chiamati Default, Disconnect e Winlogon, le tre Windowstation dei tre account Local System, Network Service e Local Service, e due Windowstation aggiuntive per servizi avviati con altri account.

Desktop Heap Information Monitor Tool (Version 8.1.2925.0)
Copyright (c) Microsoft Corporation. All rights reserved.
-------------------------------------------------------------

Windowstation: (WinSta0) SessionID: 0
Desktop: (Default) Addr: bc630000

Desktop Heap 3145728 (0x 300000) Bytes
Committed 2113536 (0x 204000) Bytes
Uncommitted 1032192 (0x fc000) Bytes
Allocated 2032816 (0x 1f04b0) Bytes
Total Freed 80720 (0x 13b50) Bytes
Unused 1112912 (0x 10fb50) Bytes
Used Rate ( 64.6) %
-------------------------------------------------------------

Windowstation: (WinSta0) SessionID: 0
Desktop: (Disconnect) Addr: bc620000

Desktop Heap 65536 (0x 10000) Bytes
Committed 4096 (0x 1000) Bytes
Uncommitted 61440 (0x f000) Bytes
Allocated 2648 (0x a58) Bytes
Total Freed 1448 (0x 5a8) Bytes
Unused 62888 (0x f5a8) Bytes
Used Rate ( 4.0) %
-------------------------------------------------------------

Windowstation: (WinSta0) SessionID: 0
Desktop: (Winlogon) Addr: bc600000

Desktop Heap 131072 (0x 20000) Bytes
Committed 20480 (0x 5000) Bytes
Uncommitted 110592 (0x 1b000) Bytes
Allocated 8560 (0x 2170) Bytes
Total Freed 11920 (0x 2e90) Bytes
Unused 122512 (0x 1de90) Bytes
Used Rate ( 6.5) %
-------------------------------------------------------------

Windowstation: (Service-0x0-3e7$) SessionID: 0
Desktop: (Default) Addr: bc930000

Desktop Heap 524288 (0x 80000) Bytes
Committed 65536 (0x 10000) Bytes
Uncommitted 458752 (0x 70000) Bytes
Allocated 49712 (0x c230) Bytes
Total Freed 15824 (0x 3dd0) Bytes
Unused 474576 (0x 73dd0) Bytes
Used Rate ( 9.5) %
-------------------------------------------------------------

Windowstation: (Service-0x0-3e4$) SessionID: 0
Desktop: (Default) Addr: bc9b0000

Desktop Heap 524288 (0x 80000) Bytes
Committed 16384 (0x 4000) Bytes
Uncommitted 507904 (0x 7c000) Bytes
Allocated 15344 (0x 3bf0) Bytes
Total Freed 1040 (0x 410) Bytes
Unused 508944 (0x 7c410) Bytes
Used Rate ( 2.9) %
-------------------------------------------------------------

Windowstation: (Service-0x0-3e5$) SessionID: 0
Desktop: (Default) Addr: bca30000

Desktop Heap 524288 (0x 80000) Bytes
Committed 8192 (0x 2000) Bytes
Uncommitted 516096 (0x 7e000) Bytes
Allocated 7568 (0x 1d90) Bytes
Total Freed 624 (0x 270) Bytes
Unused 516720 (0x 7e270) Bytes
Used Rate ( 1.4) %
-------------------------------------------------------------

Windowstation: (SAWinSta) SessionID: 0
Desktop: (SADesktop) Addr: bcab0000

Desktop Heap 524288 (0x 80000) Bytes
Committed 4096 (0x 1000) Bytes
Uncommitted 520192 (0x 7f000) Bytes
Allocated 2320 (0x 910) Bytes
Total Freed 1776 (0x 6f0) Bytes
Unused 521968 (0x 7f6f0) Bytes
Used Rate ( 0.4) %
-------------------------------------------------------------

Windowstation: (__X78B95_89_IW) SessionID: 0
Desktop: (__A8D9S1_42_ID) Addr: bcb30000

Desktop Heap 524288 (0x 80000) Bytes
Committed 4096 (0x 1000) Bytes
Uncommitted 520192 (0x 7f000) Bytes
Allocated 2320 (0x 910) Bytes
Total Freed 1776 (0x 6f0) Bytes
Unused 521968 (0x 7f6f0) Bytes
Used Rate ( 0.4) %
-------------------------------------------------------------

Alla prossima!

Mario Raccagni
Senior Support Engineer
Platform Development Support Team