Ki nyúlt le 512 MB RAM-ot?

Ahogy azt a múltkor írtam, adva volt egy szerver, ahol gyanúsan kevés volt a szabad memória, és senki nem akart bevallani kb. 500 MB-nyi memóriafoglalást. A szerver Windows Server 2003 volt, SQL 2000 és IIS futott még rajta. Ezenkívül a különös ismertetőjele még az, hogy szegény nem létezik fizikailag, egy VMware virtuális gép egy ESX szerveren. Nézegettem a teljesítményszámlálókat, feladatkezelőt, és sehogy se akart összejönni az 1 GB-nyi fizikai memória foglalás, bárhogy is adtam össze a különböző számokat:) Végül azzal zártam le ideiglenesen, hogy biztos az ESX van a dolog mögött, ott lehet valami olyasmit, hogy a virtuális gép nem használja ki a teljes memóriát, amit neki kiosztottunk. Ezt később meg is erősítette az ESX gép adminja, a szerver átmenetileg eléggé túl van terhelve, és több virtuális memória lett kiosztva összesen, mint amennyi fizikai van (ezt hívják memory overcommitmentnek). Így aztán az ESX elég spórolós a memóriával, hogy mindenkinek jusson elég. Ezt egy úgynevezett memory balloon technológiával oldják meg (lásd The Role of Memory in VMware ESX Server 3, van szép kép is benne, hogy hogyan lehet a memória lufit felfújni meg leereszteni:), egy driver fut a virtuális gépen, ami úgy tesz, mintha egy csomó memóriát lefoglalna, és azt a virtuális gép többi része nem kaphatjta így meg. Ok, most már tudjuk mi csinálja, csak azt nem, hogy hogyan!:) Kíváncsi voltam, és nekiálltam megkeresni, hogy hol látszik ez a ballooning, hova dugja el a memóriát az ESX.

Ahogy azt az előző bejegyzésben is írtam, perfmonmal és Process Explorerrel nem mentem sokra. Még egyszer nekiálltam, most már a Windows Internals könyv megfelelő fejezetét nézve folyamatosan, de még mindig hiány volt. A folyamatok által használt fizikai memória (munkakészlet, working set) 300 MB körül volt, és még a folyamatok által lefoglalt összes virtuális memória (committed private virtual bytes) is 400 MB, ennyi kéne, ha minden memóriában lenne, de ennek egy részét a lapozófájlban tartja. A rendszer is kb. 80 MB-ot foglal, és a system cache-re is 150 MB-ot ír ki a feladatkezelő (ráadásul ennek egy része már az előbb említett 80 MB). Szóval így nem jutottam eredményre.

Már csak egy lehetőség van, hogy lássuk, hogy néz ki a memórialapok tényleges felosztása: a !memusage és !vm parancsok a kernel debuggerben. [Vistán és Server 2008-on már lehetne használni ezt a kis eszközt: Alex Ionescu, MemInfo: Peer Inside Memory Manager Behavior on Windows Vista and Server 2008]. Mivel úgyis csak teszt szerver volt, és nem hagyott nyugodni a dolog, felraktam a Debugging Toolst, lesz ami lesz:)

Lássuk akkor mit mond a !memusage parancs!

Microsoft (R) Windows Debugger Version 6.8.0004.0 X86
Copyright (c) Microsoft Corporation. All rights reserved.

Connected to Windows Server 2003 3790 x86 compatible target, ptr64 FALSE
Symbol search path is: SRV*c:\windows\symbols*http://msdl.microsoft.com/download/symbolsExecutable search path is:
*******************************************************************************
WARNING: Local kernel debugging requires booting with kernel
debugging support (/debug or bcdedit -debug on) to work optimally.
*******************************************************************************
Windows Server 2003 Kernel Version 3790 (Service Pack 2) MP (2 procs) Free x86
compatibleProduct: LanManNt, suite: Enterprise TerminalServer SingleUserTS
Built by: 3790.srv03_sp2_gdr.070304-2240
Kernel base = 0x80800000 PsLoadedModuleList = 0x808af9c8
Debug session time: Sat Jan 19 20:40:09.145 2008 (GMT+1)
System Uptime: 9 days 17:34:30.500
lkd> !memusage
loading PFN database
loading (100% complete)
Compiling memory usage data (99% Complete).
Zeroed: 880 ( 3520 kb)
Free: 5 ( 20 kb)
Standby: 24251 ( 97004 kb)
Modified: 39 ( 156 kb)
ModifiedNoWrite: 2 ( 8 kb)
Active/Valid: 236810 (947240 kb)
Transition: 43 ( 172 kb)
Bad: 0 ( 0 kb)
Unknown: 0 ( 0 kb)
TOTAL: 262030 (1048120 kb)

Nincs mese, ~950 MB-nyi aktív lap van, tehát nem cache-ben van elrejtve, hanem valaki tényleg használja. Nézzünk akkor egy !vm parancsot, hátha kiderül, ki a bűnös!

lkd> !vm	

*** Virtual Memory Usage ***
Physical Memory: 262002 ( 1048008 Kb)
Page File: \??\C:\pagefile.sys
Current: 2095104 Kb Free Space: 1882420 Kb
Minimum: 2095104 Kb Maximum: 4190208 Kb
Available Pages: 33004 ( 132016 Kb)
ResAvail Pages: 48255 ( 193020 Kb)
Locked IO Pages: 294 ( 1176 Kb)
Free System PTEs: 253988 ( 1015952 Kb)
Free NP PTEs: 32766 ( 131064 Kb)
Free Special NP: 0 ( 0 Kb)
Modified Pages: 426 ( 1704 Kb)
Modified PF Pages: 428 ( 1712 Kb)
NonPagedPool Usage: 3935 ( 15740 Kb)
NonPagedPool Max: 51711 ( 206844 Kb)
PagedPool 0 Usage: 4334 ( 17336 Kb)
PagedPool 1 Usage: 526 ( 2104 Kb)
PagedPool 2 Usage: 517 ( 2068 Kb)
PagedPool 3 Usage: 510 ( 2040 Kb)
PagedPool 4 Usage: 489 ( 1956 Kb)
PagedPool Usage: 6376 ( 25504 Kb)
PagedPool Maximum: 43008 ( 172032 Kb)
Shared Commit: 4842 ( 19368 Kb)
Special Pool: 0 ( 0 Kb)
Shared Process: 4627 ( 18508 Kb)
PagedPool Commit: 6381 ( 25524 Kb)
Driver Commit: 1476 ( 5904 Kb)
Committed pages: 261768 ( 1047072 Kb)
Commit limit: 763782 ( 3055128 Kb)

Total Private: 93063 ( 372252 Kb)

Ok, nézzük akkor:

  • 1 GB fizikai memória van (Physical memory),
  • ebből 128 MB szabad (Available Pages),
  • 15 MB-ot használ a nem lapozható poolra a kernel (NonPagedPool Usage),
  • a lapozható pool is csak 25 MB (PagedPool Usage),
  • Driver Commit is csak 5 MB,
  • és végül a Total Private is csak 363 MB.

Megint valahogy kevés. Így aztán visszamentem a !memusage-hoz, mert az kilistázza a végén a részletes foglalást, ilyesmi formában:

Control Valid Standby Dirty Shared Locked PageTables  name
85d63b88 1356 396 0 100 0 0 mapped_file( msi.dll )
85c2e078 80 1356 0 0 0 0 mapped_file( ext.dll )
861644d0 17724 16 0 440 0 0 mapped_file( SecEvent.Evt )
...
1f62a 456 0 0 448 0 0 Page File Section
30ee7 4 0 0 0 0 0 Page File Section
...
--------   920     32     0 ----- -----   116  process ( VMwareUser.exe ) 858ee938
-------- 9872 4080 0 ----- ----- 292 process ( sqlservr.exe ) 85d5b020
-------- 384 168 0 ----- ----- 24 process not found (0)
...
--------  2164      0     0 -----     0 -----  driver ( ntoskrnl.exe )
-------- 144 0 0 ----- 0 ----- driver ( hal.dll )
-------- 12 0 0 ----- 0 ----- driver ( kdcom.dll )
...
-------- 17436 208 4 ----- 0 32 ( Paged Pool )
-------- 4708 32 184 ----- 0 184 ( Kernel Stacks )
-------- 79344 0 0 ----- 0 1728 ( NonPaged Pool )
Summary 943676 96384 204 22652 1148 8548 Total

Szépen látszik, hogy milyen célra foglal le fizikai lapokat az operációs rendszer. A gond csak az, hogy ez vagy egy 1300 sorból álló lista, tehát kicsit nehéz áttekinteni a debugger parancssoros kimenetén:)

Úgyhogy fogtam az egészet és kiraktam egy szöveg fájlba. Igazából egy CSV fájl lenne jó belőle, és akkor azt lehet Excelben rendezgetni. Aznap korábban pont hasonlóval szenvedtem, hogy Powershellel CSV-t csináljak egy parancssoros fájl kimenetéből (erről is remélhetőleg még írok később, érdekes volt;), úgyhogy most már viszonylag könnyen ment a dolog, csak annyit kell, hogy az egyes oszlopok között lévő tetszőleges számú szóközt egy darab ; jelre lecserélni (magyar területi beállítások vannak a gépemen, így a CSV-ben a ; határoló karakter)

$a = Get-Content "a.txt"

foreach ($line in $a)
{
$line = [string] $line #needed cast to work Split properly
$terms = $line.Split(' ')
$newline = "" foreach ($term in $terms)
{
if ($term.Length -ne 0)
{
$newline += $term + ";" } } Add-Content "b.csv" $newline
}

(Arra kell csak figyelni, hogy az Add-Contentben az első paraméter a kimenet, a második, hogy mit írjon bele, és nem fordítva. Nekem sikerült felcserélnem, és így hihetetlen gyorsan sikerült vagy 1000 fájlt generálnia:))

No most, hogy megvan a CSV fájl, elkezdhetjük összeszámolni. Ez jött ki:

kernel	       110276
process 126580
pf section 4476
mapped files 97484

Még jó látható hiányunk van. Már csak egy sor volt hátra, és az adta meg a választ:

ffffebcb 604860      0     0     0     0     0    AWE

Hah, itt van a hiányzó 600 MB!! Szóval az AWE (Address Windows Extension) segítségével foglalja le a memóriát, és ezért nem látszik az sehol:) Végül is okos, mert az így lefoglalt lapok nem lapozhatóak, nem megoszthatóak, tehát azokhoz tényleg senki nem fog megpróbálni hozzányúlni. Így tulajdonképpen nem is baj, hogy nincsenek ott, és időközben "kölcsön adatuk" másnak;)

Miután ezt az egészet végigjátszottam, rákerestem még egyszer a ballooningra, hátha van valami részlet is róla. Elég gyorsan találtam is: Memory Resource Management in VMware ESX Server. 3.2 fejezet pont erről szól, ott azt írja, hogy a Windowson a megvalósításban a MmAllocatePagesForMdl() és MmProbeAndLockPages() függvényeket írja. Rákeresve ezekre az egyik sysinternals hírlevélben írják, hogy "The AWE API has equivalent kernel-mode interfaces on which kernel32.dll bases the user-mode APIs" és felsorolják az MmAllocatePagesForMdl és MmFreePagesFromMdl függvényeket. No mindegy, ehhez a részéhez már nem értek, a lényeg, hogy meglett a hiányzó 500 MB:)

Még egy dolgot megnéztem, hogy miket használ pontosan a ballooning driver. A C:\Program Files\VMware\VMware Tools\Drivers\memctl\vmmemctl.sys fájlban van implementálva, és a Dependency Walker azt mondja róla, hogy az ntoskrnl.exe-ből ezeket a függvényeket használja:

image

No, megint tanultam valamit 🙂

Advertisements
Kategória: Opre | Közvetlen link a könyvjelzőhöz.

Egy hozzászólás a(z) 0ejegyzéshez

  1. Tamas szerint:

    Jó kis cikk, tanultam belőle.

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés / Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés / Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés / Módosítás )

Google+ kép

Hozzászólhat a Google+ felhasználói fiók használatával. Kilépés / Módosítás )

Kapcsolódás: %s