메모리 할당 관련 에러가 발생할 경우 찾아볼 수 있는 명령

Server 운영체제에서 Kernel Module 을 개발하다 보면 메모리 할당에 실패하는 경우가 간혹 나타난다. 이때 어떤 Module 이 메모리를 많이 사용하는지 아니면 다른 것 때문에 메모리 할당이 ��패하는지 구분하기 힘들때가 있다. 이때 유용한 몇가지 명령을 알아보자.

 

!vm
Virtual memory 의 현황을 알려준다. 메모리 부족 현상이 발생하였을 경우 우선적으로 !vm 명령을 실행하여 Free 메모리의 상태를 확인해 보아야 한다.


1) Kernel Module 이 Load 되지 않는 다면 Free System PTEs 를 확인해 보아야 한다.  Kernel Module 이 Load 될 공간과 Stack 공간등이 할당되는 영역인데 5000 이하로   떨어지면 Kernel Module 이 Load 되지 않는다. User Mode Memory 를 3GB로 설정  하였을 경우 이 공간이 부족하게될 가능성이 높다.

2) NonPagedPool, PagedPool 이 할당되지 않는다면 할당이 실패할 때마다 pool allocations  have failed 값이 1씩 증가하게 된다. NonPagedPool Usage 와 Max 값 그리고 PagedPool Usage 와 Max 값을 비교해 보고 현재의 할당량을 확인해 보아 메모리가 부족한지 확인해야 한다.
  - Max 에 가깝게 Pool 을 사용하고 있다면 !poolused, !pool 등의 명령을 통해 어떤 Tag을 사용하는 Kernel Module 이 Pool 을 많이 사용하는지 확인해 봐야 한다.
  - 남아있는 메모리는 있는데 할당이 되지 않는다면 !pool 명령으로 pool 이 단편화 되었는지 확인해 보아야 한다. (아직 단편화가 원인인지는 확인되지 않았으나 pool 단편화로 인해서 free 로 되어 있는 pool 보다 큰 크기의 pool 할당은 실패하는 것으로 생각된다.

kd> !vm 1

*** Virtual Memory Usage ***
      Physical Memory:     16270   (   65080 Kb)
      Page File: \??\E:\pagefile.sys
         Current:     98304Kb Free Space:     61044Kb
         Minimum:     98304Kb Maximum:       196608Kb
      Available Pages:      5543   (   22172 Kb)
      ResAvail Pages:       6759   (   27036 Kb)
      Locked IO Pages:       112   (     448 Kb)
Free System PTEs:    45089   (  180356 Kb)
      Free NP PTEs:         5145   (   20580 Kb)
      Free Special NP:       336   (    1344 Kb)
      Modified Pages:        714   (    2856 Kb)
NonPagedPool Usage:    877   (    3508 Kb)
      NonPagedPool Max:     6252   (   25008 Kb)
      PagedPool 0 Usage:     729   (    2916 Kb)
      PagedPool 1 Usage:     432   (    1728 Kb)
      PagedPool 2 Usage:     436   (    1744 Kb)
      PagedPool Usage:      1597   (    6388 Kb)
      PagedPool Maximum:   13312   (   53248 Kb)
********** 4270 pool allocations have failed **********
      Shared Commit:        1097   (    4388 Kb)
      Special Pool:          229   (     916 Kb)
      Shared Process:       1956   (    7824 Kb)
      PagedPool Commit:     1597   (    6388 Kb)
      Driver Commit:         828   (    3312 Kb)
      Committed pages:     21949   (   87796 Kb)
      Commit limit:        36256   (  145024 Kb)

 

!fraq

NonPagedPool 이 얼마나 사용되고 단편화 되었는지 알려준다.
kd> !frag 1
  NonPaged Pool Fragmentation
index:  0 number of fragments:     4  bytes:    128
index:  1 number of fragments:     0  bytes:      0
index:  2 number of fragments:     2  bytes:    192
index:  3 number of fragments:     0  bytes:      0
...
index: 20 number of fragments:     0  bytes:      0
index: 21 number of fragments:     0  bytes:      0
index: 22 number of fragments:     1  bytes:   7232
index: 23 number of fragments:     0  bytes:      0
index: 24 number of fragments:     0  bytes:      0
Number of fragments:      11 consuming    9344 bytes
NonPagedPool Usage:  1105920 bytes

!poolused
Gflags 를 사용해서 Pool Tag 를 활성화 시켜야 한다. (Windows 2003 이후에는 기본이 활성화) PagedPool 이나 NonPagedpool 할당이 실패할 경우 이 명령으로 Pool 의 사용량을 확인해야 한다. 현재 Pool 의 사용량을 Tag 를 기준으로 보여준다. 어떤 Tag 가 Pool 을 많이 사용하는지를 알아내고 어떤 Kernel Module 이 해당 Tag 를 사용하는지 확인하여 원인 제공 Module 을 찾을 수 있다.

0: kd> !poolused
   Sorting by  Tag

  Pool Used:
            NonPaged            Paged
Tag    Allocs     Used    Allocs     Used
1394        1      520         0        0UNKNOWN pooltag '1394', please update pooltag.txt
1MEM        1     3368         0        0UNKNOWN pooltag '1MEM', please update pooltag.txt
2MEM        1     3944         0        0UNKNOWN pooltag '2MEM', please update pooltag.txt

....

thdd        0        0         1    20480DirectDraw/3D handle manager table
usbp       18    77056         2       96UNKNOWN pooltag 'usbp', please update pooltag.txt
vPrt        0        0        18    68160UNKNOWN pooltag 'vPrt', please update pooltag.txt
TOTAL     3570214 209120008     38769 13066104

!pool

특정 Pool 이나 System-wide 한 Pool 의 정보를 볼 수 있다. 특정 Pool 의 경우 해당 Pool 에 할당된 Tag 를 볼 수 있으며 System-Wide 의 경우 전체 Pool 영역중 할당된 것과 아직 할당되지 않은 영역을  알 수 있다.  Pool 단편화가 발생하여 적당한 크기의 free pool 이 없을 경우 큰 크기의 pool 할당이 실패할 수 있다.

kd> !pool e1001050
e1001000 size:   40 previous size:    0  (Allocated)  MmDT
e1001040 size:   10 previous size:   40  (Free)       Mm 
*e1001050 size:   10 previous size:   10  (Allocated) *ObDi

lkd> !pool
Paged Pool: e1000000 .. f73fffff
e1000000: 1000 - busy
e1001000: 1000 - busy
e1002000: 1000 - busy
e1003000: 1000 - busy
e1004000: 1000 - busy
e1005000: 1000 - busy

...

e7032000: d000 - busy
e703f000: 22000 - busy
e7061000: 8000 - busy
e7069000: 28000 - busy
e7091000: 170000 - free
e7201000: 101ff000 - free