Windows의 「메모리 사용량」은 무엇을 나타내는가 ── Working Set·Private Bytes·Commit·페이지 파일을 올바르게 읽는 법

· · Windows, Windows 개발, 메모리 관리, Working Set, Private Bytes, Commit, 페이지 파일, 성능 모니터링, 장애 조사, Sysinternals

작업 관리자에는 어떤 프로세스의 「메모리」가 1.2GB로 표시되어 있다. 그런데 Process Explorer에서는 Working Set이 1.5GB, Private Bytes가 2.4GB이고, VMMap에서는 Size가 그보다도 더 크다. 시스템 전체를 보면 「커밋됨 19.6/31.8GB」로 나온다.

그렇다면 이 앱은 결국 몇 GB의 메모리를 사용하고 있는 것일까?

답은, 무엇을 알고 싶은지에 따라 봐야 할 숫자가 달라진다는 것입니다. 지금 RAM에 올라와 있는 양을 알고 싶은지, 그 프로세스 고유의 할당량을 알고 싶은지, 시스템이 앞으로도 지원하겠다고 약속한 양을 알고 싶은지, 단순히 가상 주소를 확보한 범위를 알고 싶은지에 따라 봐야 할 지표는 달라집니다.

Windows의 메모리 지표가 어려운 이유는, 모두 「메모리」라는 같은 말로 표시되지만 실제로는 다음과 같은 서로 다른 축을 측정하고 있기 때문입니다.

  • 주소 공간을 얼마나 사용하고 있는가
  • 커밋(Commit)을 얼마나 소비하고 있는가
  • 현재 물리 RAM에 상주하고 있는가
  • 그 페이지가 프로세스 고유인지, 공유 가능한지
  • 시스템 전체에서 앞으로 얼마나 더 할당을 지원할 수 있는가

이 글에서는 Windows 10/11 및 현행 Windows Server에서 앱의 메모리 증가나 시스템 전체의 메모리 부족을 조사하는 사람을 대상으로, Working Set, Private Working Set, Private Bytes, Commit, Virtual Bytes, 페이지 파일, Available, 페이지 폴트의 관계를 한 장으로 정리합니다.

.NET 오브젝트가 회수되지 않는 원인을 추적하는 절차는 「.NET에서 GC 대기와 메모리 누수를 구별하는 법」에서, VMMap이나 Process Explorer의 구체적인 조작은 「Process Explorer / Handle / VMMap 실전」에서 자세히 다루고 있습니다. 이 글은 그 전제가 되는 Windows OS 쪽 숫자를 읽는 법에 집중합니다.

1. 먼저 결론

  • Working Set은 현재 RAM에 상주하고 있는 페이지입니다. 프로세스 고유의 페이지뿐만 아니라, DLL 코드나 메모리 매핑 파일처럼 다른 프로세스와 공유할 수 있는 페이지도 포함합니다.1
  • Private Working Set은 Working Set 중에서 현재 그 프로세스에만 속하는 부분입니다. 「지금 이 프로세스가 고유하게 점유하고 있는 RAM」을 보는 근사값으로 사용할 수 있지만, 앱이 확보한 전체 양은 아닙니다.2
  • Private Bytes는 그 프로세스 고유의 커밋(Commit) 양입니다. 현재 RAM에 올라와 있는지 여부와는 별개의 지표입니다. Win32 API 구조체에 있는 PagefileUsage도, 현재의 Windows에서는 실질적으로 같은 Commit Charge를 나타내며, 페이지 파일에 실제로 기록된 바이트 수가 아닙니다.2
  • 작업 관리자의 「커밋됨 X/Y」는 X가 시스템 전체의 현재 커밋 양, Y가 커밋 상한입니다. X는 페이지 파일 사용량이 아닙니다. Y는 대체로 RAM과 페이지 파일의 합계로 결정됩니다.3
  • Reserve와 Commit은 다릅니다. 가상 주소를 Reserve하기만 했다면 그 범위를 나중에 사용하기 위해 확보해 둔 것일 뿐이며, RAM도 커밋 상한도 그만큼 소비하지 않습니다.45
  • 페이지 폴트(Page Fault)는 반드시 디스크 I/O를 의미하지는 않습니다. RAM 안에서 해결할 수 있는 소프트 폴트(soft fault)와, 페이지 파일·실행 파일·메모리 매핑 파일 등에서 읽어 오는 하드 폴트(hard fault)가 있습니다.16
  • 메모리 누수는 한 번의 값이 아니라, 같은 부하를 반복했을 때의 기울기로 판단합니다. 특히 Private Bytes나 그 내역이 처리 종료 후에도 단계적으로 계속 증가하며, 같은 정상 상태로 돌아오지 않는지를 봅니다.

한 문장으로 정리하면, Working Set은 「지금 RAM에 있는 양」, Private Bytes는 「이 프로세스 고유로 약속된 양」, Commit은 「시스템 전체가 약속한 양」입니다.

Windows의 주요 메모리 지표 고르기알고 싶은 대상이 RAM 상주량, 프로세스 고유 커밋량, 시스템 전체 커밋량, 가상 주소 범위 중 무엇인지에 따라 봐야 할 지표가 달라진다지금 RAM에 있는 양프로세스 고유의 약속량시스템 전체의 약속량확보한 주소 범위메모리 사용량으로 무엇을 알고 싶은가Working SetPrivate BytesSystem CommitVirtual Bytes / Reserved물리 RAM에 상주프로세스 고유 CommitCommit Limit과 비교가상 주소 공간

그림 1: “메모리가 많다”는 관찰을, 먼저 4가지 질문으로 분해한다.

2. 「메모리 사용량」을 4가지 축으로 나누기

먼저 Windows의 메모리를 「하나의 막대」가 아니라 4가지 축으로 생각합니다.

1개 페이지를 분류하는 4가지 독립적인 축가상 주소 상태, 커밋된 페이지의 뒷받침, 물리 RAM 상주 여부, 다른 프로세스와의 공유 가능성을 각각 따로 확인한다1개 페이지를 4가지 축으로 보기주소 상태Free / Reserved / Committed뒷받침Page-file-backed / File-backedRAM 상주Resident / Not resident공유 가능성Private / Shareable

그림 2: 페이지 하나라도 주소 상태·뒷받침·상주·공유성은 각각 별도로 결정된다.

Mapped는 Free·Reserved·Committed와 나란한 주소 상태가 아니라 영역의 종류입니다. 매핑된 뷰의 페이지도 Committed가 될 수 있습니다. 또한 Private는 뒷받침 매체가 아니라 공유 가능성의 분류입니다. 그래서 뒷받침은 Page-file-backed인지 File-backed인지, 공유 가능성은 Private인지 Shareable인지를 따로 읽습니다.

이 4가지 축을 조합하면 대표적인 지표의 관계는 다음과 같습니다.

페이지 상태 Working Set Private Working Set Private Bytes Virtual Bytes 계열
프로세스 고유·커밋됨·RAM 상주 포함 포함 포함 포함
프로세스 고유·커밋됨·RAM 비상주 미포함 미포함 포함 포함
DLL이나 매핑 파일의 공유 페이지·RAM 상주 포함 원칙적으로 미포함 원칙적으로 미포함 포함
예약됨이지만 미커밋 미포함 미포함 미포함 포함될 수 있음
미사용 주소 범위 미포함 미포함 미포함 통상 미포함
페이지 종류와 주요 메모리 지표의 대응 관계Private로 상주하는 페이지, Private로 비상주인 페이지, 공유로 상주하는 페이지, 예약만 된 범위가 어느 지표에 포함되는지 보여준다Private · Commit됨 · RAM 상주Private · Commit됨 · RAM 비상주공유 페이지 · RAM 상주Reserved · 미CommitWorking SetPrivate Working SetPrivate BytesVirtual Bytes 계열

그림 3: Working Set과 Private Bytes는 서로 다른 페이지 집합을 세기 때문에 단순한 포함 관계가 되지 않는다.

여기서 중요한 점은, Working Set과 Private Bytes가 단순한 포함 관계가 아니라는 것입니다.

Private Bytes에는 프로세스 고유이지만 지금은 RAM에 상주하지 않는 페이지가 포함됩니다. 반면 Working Set에는 DLL 코드나 공유 메모리처럼 Private Bytes에는 세지 않는 공유 페이지가 포함됩니다. 그래서 프로세스나 시점에 따라 Working Set이 Private Bytes보다 클 수도 있고, 그 반대일 수도 있습니다.

또한 여러 프로세스의 Working Set을 단순히 합산하면, 공유 DLL 등 동일한 물리 페이지를 여러 번 셀 가능성이 있습니다. 「각 프로세스의 Working Set 합계 = 사용 중인 RAM」이라고는 할 수 없습니다.

3. 가상 주소 공간 ── Reserve와 Commit은 다른 것

3.1. 가상 주소는 물리 RAM의 번지가 아니다

각 프로세스는 자신만의 가상 주소 공간을 가집니다. 앱이 다루는 포인터는 물리 RAM의 위치를 직접 가리키는 것이 아니라, Windows가 페이지 테이블을 사용해 가상 주소를 물리 페이지나 파일 상의 데이터로 대응시킵니다.7

이 때문에 64GB RAM을 탑재한 PC라도, 어떤 32bit 프로세스가 사용할 수 있는 가상 주소 공간은 보통 그보다 훨씬 작다는 일이 일어납니다. 반대로 물리 RAM보다 큰 가상 주소 공간을 가진 64bit 프로세스도 흔합니다.

3.2. Reserved는 「주소를 확보해 둔」것뿐

VirtualAllocMEM_RESERVE는 나중에 사용하기 위해 연속된 가상 주소 범위를 확보합니다. 이 단계에서는 페이지에 물리 스토리지가 연결되지 않으며, 그 범위를 읽거나 쓸 수도 없습니다.45

예를 들어 데이터베이스나 런타임이 향후 확장을 위해 8GB의 주소 범위를 Reserve해 두었다 해도, 그것만으로 8GB의 RAM이나 8GB의 Private Bytes를 소비한 것은 아닙니다.

3.3. Committed는 「필요할 때 지원하겠다」고 약속한 상태

MEM_COMMIT은 해당 가상 페이지를 Committed 상태로 만들고, Windows가 필요한 뒷받침을 제공하겠다고 약속하는 조작입니다. 실제로 읽기·쓰기·실행이 허용되는지는 PAGE_READONLY, PAGE_READWRITE, PAGE_EXECUTE, PAGE_NOACCESS 등의 페이지 보호로 별도로 결정되며, Commit이 완료되었다는 것 자체가 「읽고 쓸 수 있음」을 의미하지는 않습니다. 커밋한 시점에 시스템의 Commit Charge에 계상되지만, 실제 물리 페이지는 최초 접근 시점까지 할당되지 않는 경우가 있습니다. 처음 접근한 페이지는 0으로 초기화되며, Demand-zero fault를 거쳐 Working Set으로 들어갑니다.51

따라서 같은 「확보했다」라도 다음 3단계가 있습니다.

Reserve부터 Commit과 RAM 상주까지의 3단계가상 주소를 예약하고, 페이지를 커밋하고, 최초 접근으로 물리 페이지가 할당되어 Working Set으로 들어가는 흐름을 보여준다MEM_COMMIT최초 접근 - Demand-zero fault미접근이면MEM_RESERVE - 주소 범위 확보Virtual Bytes 계열에 반영Commit됨 - 페이지 보호에 따라 접근 가능Private Bytes / System Commit에 반영물리 페이지를 할당해 RAM 상주Working Set에 반영Commit됨이지만 비상주

그림 4: Reserve, Commit, 최초 접근은 서로 다른 사건이며, 각각 다른 지표를 움직인다.

이 3단계가 각각 Virtual Bytes 계열, Private Bytes, Working Set의 숫자를 따로따로 움직입니다.

3.4. 여유 RAM이 있어도 OutOfMemory가 발생하는 이유

메모리 할당의 성패는 여유 RAM만으로 결정되지 않습니다.

  • 프로세스의 가상 주소 공간을 다 써버렸다
  • 필요한 크기의 연속된 여유 주소 범위가 없다
  • 시스템 전체의 Commit Charge가 Commit Limit에 도달했다
  • Job Object, 컨테이너, 런타임, 라이브러리에 자체 상한이 있다
  • 32bit 프로세스이다
  • 네이티브 힙이 단편화되어 있다

64bit Windows에서도 32bit 프로세스의 사용자 모드 가상 주소 공간은 IMAGE_FILE_LARGE_ADDRESS_AWARE가 비활성화되어 있으면 보통 2GB입니다. 이 플래그가 활성화된 32bit 앱은 64bit Windows에서 최대 4GB까지 사용할 수 있습니다.8

그래서 「PC에는 20GB의 여유 RAM이 있는데도 32bit 앱이 1.6GB 부근에서 실패한다」는 모순이 아닙니다. RAM 문제가 아니라 주소 공간의 단편화나 상한에 부딪혔을 가능성이 있습니다.

4. Working Set ── 지금 RAM에 올라와 있는 페이지

Working Set은 프로세스의 가상 주소 공간 중에서 현재 물리 RAM에 상주하고 있는 페이지의 집합입니다.1

여기에는 다음이 뒤섞여 있습니다.

  • 프로세스 고유의 힙과 스택
  • EXE와 DLL의 코드·읽기 전용 데이터
  • 메모리 매핑 파일
  • 공유 메모리
  • Copy-on-write 이후 그 프로세스 고유가 된 페이지
  • 런타임이나 각종 라이브러리가 접근한 페이지

4.1. Working Set이 늘어나도, 할당이 늘어난 것이라고는 할 수 없다

이미 커밋되어 있던 페이지에 처음 접근하면, Private Bytes는 그대로인 채 Working Set만 늘어나는 경우가 있습니다. 큰 파일을 메모리에 매핑해 순서대로 읽은 경우에도, 파일에서 유래한 페이지가 Working Set에 들어가고 Private Bytes는 거의 늘어나지 않는 경우가 있습니다.

반대로 Windows가 메모리 압박에 대응해 Working Set을 Trim하면, 앱이 논리적으로는 같은 메모리를 유지한 채로 Working Set만 줄어듭니다. 나중에 다시 접근하면 페이지 폴트를 거쳐 돌아옵니다.

따라서 Working Set의 하락이 「앱이 해제했다」는 것을, 상승이 「앱이 새로 확보했다」는 것을 의미하지는 않습니다.

Working Set만 증감하는 전형적인 흐름같은 Commit된 페이지가 최초 접근으로 RAM에 들어가고, Trim으로 비상주가 되고, 재접근으로 돌아오는 동안에도 Private Bytes는 계속 계상된다최초 접근메모리 압박으로 Trim재접근으로 Page Fault같은 Commit된 페이지RAM 상주비상주Working Set에 포함Working Set에 미포함Commit 중에는 Private Bytes에 계상

그림 5: Working Set은 상주 상태에 따라 오르내리지만, 같은 페이지의 Commit이 남아 있는 한 Private Bytes는 줄지 않는다.

4.2. Working Set에는 공유 페이지가 포함된다

같은 DLL의 코드 페이지를 10개 프로세스가 공유하고 있는 경우, 그 페이지는 각 프로세스의 Working Set에 나타날 수 있지만, 물리 RAM 상에는 한 벌만 존재하는 경우가 있습니다. Working Set의 합계가 탑재된 RAM을 넘어서더라도 곧바로 이상 상태는 아닙니다.

「지금 이 프로세스만 고유하게 점유하고 있는 RAM」에 가깝게 보고 싶다면 Private Working Set을 봅니다. 다만 이것도 「그 프로세스가 확보한 전체 메모리」가 아니라, 어디까지나 현재 상주 중인 Private 페이지입니다.

4.3. Working Set을 강제로 줄여도 누수는 고쳐지지 않는다

EmptyWorkingSet이나 SetProcessWorkingSetSize를 사용하면 프로세스의 Working Set에서 페이지를 몰아낼 수 있습니다. 하지만 이것은 커밋이나 힙 상의 참조를 해제하는 조작이 아닙니다. Private Bytes는 그대로인 채 겉보기 RAM 사용량만 줄어들고, 다음 접근에서 페이지 폴트가 늘어나는 경우가 있습니다.9

메모리 절감 버튼을 누른 직후에만 작업 관리자의 숫자가 작아지고, 조작을 재개하면 곧바로 원래대로 돌아온다면, 「해제」가 아니라 Working Set을 Trim했을 뿐일 수 있습니다.

5. Private Bytes ── 프로세스 고유의 커밋 양

Private Bytes는 그 프로세스 전용으로 커밋된 가상 메모리의 양입니다. 다른 프로세스와 공유할 수 없는 Commit Charge를 나타내며, 현재 RAM에 상주하고 있는지 여부는 따지지 않습니다. Microsoft의 PROCESS_MEMORY_COUNTERS_EX에서는 PrivateUsage가 이 값에 대응합니다.102

Win32 API에는 PagefileUsage라는 헷갈리는 필드 이름도 있지만, 현행 문서는 이를 「그 프로세스의 Commit Charge」로 정의하고 PrivateUsage와 같은 값이라고 설명합니다. 즉, Private Bytes 2GB는 「pagefile.sys에 2GB가 기록되어 있다」는 의미가 아닙니다.2

Private Bytes에는 대표적으로 다음이 영향을 줍니다.

  • HeapAlloc, malloc, new 등이 사용하는 네이티브 힙의 커밋
  • VirtualAlloc으로 직접 커밋한 Private Data
  • .NET GC 힙의 커밋된 영역
  • 스레드 스택 중 실제로 커밋된 부분
  • Copy-on-write 뷰(FILE_MAP_COPY)를 매핑할 때 확보되는, 뷰 전체 분량의 Commit Charge
  • 라이브러리나 디바이스 SDK가 내부에서 보유하는 Private 버퍼

FILE_MAP_COPY로 만드는 Copy-on-write 뷰에서는 각 페이지가 나중에 Private화될 수 있기 때문에, Windows는 매핑 시점에 뷰 전체를 페이지 파일로 뒷받침할 수 있도록 Commit Charge를 확보합니다. 그래서 실제로 기록하여 Private 복사본이 만들어지기 전이라도, System Commit과 프로세스의 Commit Charge(Private Bytes)가 뷰 전체 분량만큼 늘어날 수 있습니다.11

5.1. free나 GC 이후에도 Private Bytes가 줄지 않는 이유

애플리케이션 입장에서 메모리를 「해제」해도, 런타임이나 힙 할당자가 그 영역을 OS로 Decommit하지 않고 향후 재사용을 위해 보유하는 경우가 있습니다. 이 경우 앱 내부에서는 재사용이 가능하더라도 Private Bytes는 높은 채로 유지됩니다.

또한 큰 영역 중 일부만 살아남아 있다, 단편화되어 있다, 캐시나 풀이 상한까지 채워졌다와 같은 이유로도 높은 수준을 유지합니다.

따라서 Private Bytes가 높다는 것만으로는 누수를 증명할 수 없습니다. 봐야 할 것은,

  1. 같은 처리를 같은 횟수만큼 반복한다
  2. 처리 후 같은 대기 시간을 둔다
  3. Private Bytes가 같은 수준으로 돌아오는지, 일정 값에서 정체되는지
  4. VMMap이나 힙 덤프로 어느 영역·타입이 늘어났는지 확인한다

라는 시간차 비교입니다.

free나 GC 이후에도 Private Bytes가 줄지 않는 이유앱이 불필요하게 만든 영역을 할당자가 OS로 돌려주는 경우와 재사용을 위해 보유하는 경우에 Private Bytes의 변화가 다르다Decommit / Release재사용을 위해 보유앱이 free / GC로 불필요하게 만든다할당자는 OS로 돌려주는가Commit Charge가 줄어든다Private Bytes가 줄어든다영역은 Commit된 상태 그대로Private Bytes는 높은 수준 유지풀 · 캐시 · 단편화

그림 6: 앱 내부에서 재사용 가능해진 것과 OS에 Commit을 반환한 것은 같지 않다.

5.2. 누수 후보로 유력한 형태

다음과 같이 부하를 줄 때마다 바닥이 올라가는 「계단식」증가는 주의가 필요합니다.

Private Bytes
  ^
  |                    ________
  |             ______|
  |      ______|
  |_____|
  +----------------------------> 같은 처리의 반복

다만 계단식이라도 최초 JIT, 폰트, 이미지 디코더, 연결 풀, 캐시의 워밍업으로 몇 번만 증가하고 그 후 안정되는 경우가 있습니다. 증가하고 있다는 것보다 정상 상태로 수렴하지 않는다는 것이 중요합니다.

6. System Commit ── 「커밋됨 X/Y」의 정체

작업 관리자의 [성능]→[메모리]에 있는 「커밋됨 X/Y」는 시스템 전체의 지표입니다.

  • X: System Commit Charge
    현재 Windows가 시스템 전체에서 지원하겠다고 약속한 커밋된 메모리
  • Y: System Commit Limit
    시스템이 지원할 수 있는 커밋 양의 상한

Commit Limit은 대체로 물리 RAM과 모든 페이지 파일의 합계로 결정됩니다. 페이지 파일이 없는 경우에는 탑재된 RAM보다 약간 작아집니다.36

System Commit Charge와 Commit Limit의 관계프로세스 고유, 공유 섹션, 커널의 커밋이 현재값 X를 만들고, 물리 RAM과 페이지 파일이 상한 Y를 지원한다X는 Y를 넘을 수 없다각 프로세스의 Private CommitSystem Commit Charge - X페이지 파일로 뒷받침되는 공유 섹션의 Commit커널의 Commit물리 RAMSystem Commit Limit - Y페이지 파일

그림 7: X는 현재의 약속량, Y는 그 약속을 지원할 수 있는 상한이며, 페이지 파일 사용량을 표시하는 것이 아니다.

System Commit Charge에는 각 프로세스의 Private Bytes 합계뿐만 아니라, 페이지 파일로 뒷받침되는 공유 섹션의 Commit이나 커널이 소비하는 Commit도 포함됩니다. 그래서 프로세스별 Private Bytes의 합계만으로는 X를 완전히 설명할 수 없습니다.

6.1. Commit Charge는 페이지 파일 사용량이 아니다

RAM 16GB, 페이지 파일 16GB, Committed가 20/31GB인 시스템을 생각해 봅니다.

이 20GB는 「페이지 파일에 20GB를 기록했다」는 의미가 아닙니다. 20GB는 Private한 변경 가능 페이지 등에 대해, 필요해졌을 때 Windows가 RAM 또는 페이지 파일 등의 뒷받침을 준비하겠다고 약속한 총량입니다.

그 시점에는

  • 대부분이 RAM에 상주하고 있다
  • 일부가 페이지 파일로 대피되어 있다
  • Commit되었지만 아직 최초 접근이 이루어지지 않았다
  • 커널 쪽 커밋으로 소비되고 있다

라는 상태가 뒤섞여 있습니다.

페이지 파일의 실제 사용률을 보고 싶다면 Commit과는 별도로 Paging File(*)\% Usage를 확인합니다. 다만 Microsoft의 자료에서도, 페이지 파일 사용률이 높다는 것만으로는 성능 문제라고 단정할 수 없으며, Commit Limit 도달이나 Modified Page List, 실제 페이징 I/O와 함께 판단하도록 설명하고 있습니다.6

6.2. Commit Limit에 가까워지면 무슨 일이 일어나는가

System Commit Charge가 Commit Limit에 도달하면 새로운 커밋 요청을 지원할 수 없습니다. 프로세스의 메모리 할당 실패, 앱의 크래시, 조작 불능 등으로 이어집니다.3

여기서는 「여유 RAM」보다 Commit의 X/Y가 중요합니다. Working Set을 Trim해서 여유 RAM을 만들어도, Commit Charge 자체가 줄지 않으면 Commit Limit 도달은 해소되지 않습니다.

6.3. 페이지 파일의 3가지 역할

페이지 파일에는 주로 다음과 같은 역할이 있습니다.

  1. Commit Limit을 확장한다
  2. 사용 빈도가 낮은 변경된 페이지를 RAM에서 대피시킬 수 있게 한다
  3. 구성에 따라 시스템 크래시 덤프를 지원한다

페이지 파일을 비활성화하면 디스크 I/O가 반드시 줄어 빨라진다는 단순한 관계는 아닙니다. 오히려 Commit Limit을 낮추고, 변경되었지만 당장은 사용하지 않는 페이지를 RAM에 남겨 두기 쉽게 하며, 크래시 시 필요한 덤프를 채취하지 못하게 할 가능성이 있습니다.36

페이지 파일의 적절한 크기는 탑재된 RAM만으로 결정되지 않습니다. Microsoft도 피크 시의 System Commit Charge와 필요한 크래시 덤프의 종류가 시스템마다 다르기 때문에 일반화할 수 없다고 설명하고 있습니다.6

7. 물리 RAM의 내역 ── Available이 적다는 것만으로는 판단하지 않는다

물리 RAM은 사용자 프로세스의 Working Set에만 사용되는 것이 아닙니다.

  • 각 프로세스의 Working Set
  • 시스템 파일 캐시
  • Standby, Modified, Free, Zeroed 등의 페이지 리스트
  • 커널의 Paged Pool / Nonpaged Pool
  • 디바이스 드라이버가 보유하는 메모리
  • 메모리 압축 스토어
  • GPU나 디바이스와 공유·예약되는 영역
  • 하드웨어 예약

7.1. Available에는 재사용 가능한 캐시도 포함된다

Windows의 Available MBytes는 단순히 완전히 사용되지 않은 RAM만을 뜻하지 않습니다. Free, Zeroed에 더해, 필요하면 재사용할 수 있는 Standby 페이지도 포함하는 지표입니다.12

  • Free: 현재 어떤 용도로도 할당되지 않은 페이지
  • Zeroed: 다른 프로세스에 안전하게 넘길 수 있도록 0으로 채워 둔 페이지
  • Standby: Working Set에서 빠졌지만 내용을 RAM에 캐시해 두고 있는 페이지
  • Modified: 내용이 변경되어, 재사용하기 전에 적절한 뒷받침 매체로 다시 써야 하는 페이지
Working Set과 페이지 리스트 사이의 이동사용 중인 페이지가 변경되지 않았으면 Standby로, 변경되었으면 Modified로 이동하고, 재접근이나 다시 쓰기, 재사용을 거치는 흐름을 보여준다변경되지 않은 페이지를 제외변경된 페이지를 제외다시 쓰기 완료재접근다른 용도로 재사용0으로 채움할당 후 접근Working Set - 사용 중Standby - 내용을 유지한 재사용 후보Modified - 다시 쓰기 대기다른 용도로 할당Free - 미사용Zeroed - 신규 할당 가능Available에 포함

그림 8: Available에는 완전한 빈 공간뿐만 아니라, 필요하면 재사용할 수 있는 Standby도 포함된다.

「여유 RAM을 늘리기 위해 캐시를 전부 버린다」는 것이 항상 유리한 것은 아닙니다. Standby에 필요한 데이터가 남아 있다면, 다시 접근할 때 디스크를 읽지 않고 신속하게 Working Set으로 되돌릴 수 있습니다.

따라서 작업 관리자에서 Free가 적더라도, Available이 충분하고 하드 페이지 폴트나 디스크 대기가 문제가 되지 않는다면, Windows가 RAM을 캐시로 효율적으로 활용하고 있을 뿐일 수 있습니다.

7.2. 큰 프로세스가 없는데도 RAM이 줄어드는 경우

각 프로세스의 Private Working Set을 더해도 설명되지 않는 메모리 소비는 드물지 않습니다.

  • 파일 캐시나 메모리 매핑 파일
  • Nonpaged Pool / Paged Pool
  • 드라이버가 잠근 페이지
  • 공유 페이지
  • 메모리 압축
  • 가상화나 GPU 관련 할당

이 경우 프로세스 목록을 계속 들여다보기보다, Sysinternals의 RAMMap으로 Use Counts, Processes, Priority Summary, File Summary를 확인합니다. RAMMap은 물리 메모리를 용도별·페이지 리스트별·파일별로 분해하기 위한 공식 도구입니다.13

Nonpaged Pool만 계속 증가하는 경우라면, 사용자 모드 앱의 Private Bytes가 아니라 드라이버나 커널 쪽의 누수를 의심할 단계입니다.

8. Page Fault ── 많다는 것만으로는 이상이 아니다

프로세스가 현재 Working Set에 없는 페이지에 접근하면 Page Fault가 발생합니다. 이름에 「Fault」라는 말이 들어 있지만, 예외적인 고장이 아니라 가상 메모리를 동작시키는 통상적인 메커니즘입니다.1

8.1. 소프트 페이지 폴트

디스크를 읽지 않고 해결할 수 있는 것입니다.

  • 페이지가 Standby나 Transition에 남아 있다
  • 다른 프로세스의 Working Set에 같은 공유 페이지가 있다
  • Commit된 페이지에 처음 접근해 0으로 채워진 페이지를 할당한다
  • 메모리 관리자의 선행 읽기(read-ahead)로 이미 RAM에 있다

이 때문에 \Memory\Page Faults/sec가 크더라도 디스크 I/O나 지연이 발생하고 있다고는 할 수 없습니다.

8.2. 하드 페이지 폴트

디스크 상의 Backing Store에서 내용을 읽어야 하는 것입니다. 읽어 오는 곳은 페이지 파일에 국한되지 않습니다.

  • .exe.dll의 코드·데이터
  • 메모리 매핑 파일
  • 페이지 파일
소프트 페이지 폴트와 하드 페이지 폴트의 분기Working Set에 없는 페이지에 접근했을 때, 스토리지 I/O가 필요 없으면 소프트 페이지 폴트, 필요하면 하드 페이지 폴트로 처리한다아니오 - Standby·공유·Demand-zero 등Working Set에 없는 페이지에 접근스토리지 I/O가 필요한가소프트 페이지 폴트디스크를 읽지 않고 Working Set으로하드 페이지 폴트어디서 읽는가EXE / DLL메모리 매핑 파일페이지 파일읽은 후 Working Set으로

그림 9: Page Fault라는 이름만으로는 디스크 I/O 여부를 판단할 수 없다.

Microsoft는 하드 폴트를 측정하는 카운터로 \Memory\Pages/sec, \Memory\Page Reads/sec, \Memory\Pages Input/sec 등을 제시하고 있습니다. 이 값들이 높다고 해서 반드시 메모리 부족이라고는 할 수 없으므로, Available MBytes, 디스크 지연, 실제 응답 시간과 함께 상관관계를 봅니다.6

8.3. 일률적인 임계값을 두지 않는다

「Page Faults/sec가 1000을 넘으면 이상」과 같은 고정값은 스토리지, 페이지 크기, 워크로드, 접근 지역성(locality)에 따라 의미가 달라집니다.

실무에서는 다음을 같은 시간축에 나란히 놓습니다.

  • Memory\Available MBytes
  • Memory\Pages Input/sec
  • Memory\Page Reads/sec
  • 대상 디스크의 Read latency / Queue
  • 대상 프로세스의 Working Set·Private Bytes
  • 앱의 처리 시간, 타임아웃, UI 응답

부하 증가와 동시에 Available이 줄고, Pages Input/sec와 디스크 대기가 올라가며, 처리 시간도 악화된다면, 물리 메모리 압박에 의한 페이징을 의심할 근거가 갖춰집니다.

9. 어느 화면·도구에서 무엇을 볼 것인가

알고 싶은 것 처음에 볼 지표 주요 도구
지금 대상 프로세스가 RAM에 올린 양 Working Set 작업 관리자, Process Explorer, Get-Process
그중 프로세스 고유의 RAM Private Working Set / Working Set - Private 작업 관리자의 세부 정보 열, Process Explorer, PerfMon
대상 프로세스 고유의 커밋 양 Private Bytes / Commit Size Process Explorer, PerfMon, VMMap, Get-Process
프로세스의 가상 주소 범위 Virtual Bytes / Size Process Explorer, VMMap, Get-Process
시스템 전체의 커밋 여력 Committed Bytes / Commit Limit 작업 관리자 [성능], PerfMon
물리 RAM의 재사용 여력 Available MBytes 작업 관리자, PerfMon
Standby·Modified·파일 캐시의 내역 페이지 리스트·용도별 내역 RAMMap
Private Bytes 중 무엇이 늘었는가 Heap / Private Data / Managed Heap 등 VMMap, WinDbg, 런타임별 덤프
디스크를 동반하는 페이징 Pages Input/sec, Page Reads/sec, 디스크 지연 PerfMon, WPR/WPA
Windows 메모리 조사 도구 고르기대상이 1개 프로세스인지 시스템 전체인지, 한 시점인지 시계열인지, 런타임 내부까지 추적할지에 따라 사용할 도구를 고른다한 시점의 내역시계열시스템 전체물리 RAM의 내역CPU·I/O·대기까지 포함한 시간축.NET 힙네이티브 힙무엇을 가려내고 싶은가대상은 1개 프로세스인가한 시점인가 시계열인가VMMapPerfMon / PowerShell물리 RAM의 내역인가 시간축인가RAMMapWPR / WPA런타임 내부의 보유까지 추적하는가dotnet-dump / PerfViewWinDbg / Application Verifier

그림 10: 먼저 대상 범위와 시간축을 정하면 필요한 도구를 과부족 없이 고를 수 있다.

9.1. 작업 관리자

작업 관리자에서는 화면을 나누어 봅니다.

  • [프로세스]또는[세부 정보]: 개별 프로세스의 Working Set 계열, Commit Size 계열
  • [성능]→[메모리]: 시스템 전체의 In use, Available, Committed, Cached, Paged pool, Non-paged pool

「메모리」라는 열 이름만으로 판단하지 말고, [세부 정보]탭의 열 머리글을 마우스 오른쪽 버튼으로 클릭해 Working Set, Peak Working Set, Commit Size 등 필요한 열을 추가합니다. Windows 버전이나 표시 언어에 따라 열 이름이 다소 다르므로, 열의 의미를 확인한 뒤에 기록합니다.

9.2. PowerShell로 시계열 데이터 수집하기

대상 프로세스의 ID를 알고 있다면, Get-Process로 Working Set, Private Bytes, Virtual Bytes의 추이를 동시에 수집할 수 있습니다.

param(
    [Parameter(Mandatory)]
    [int]$ProcessId,

    [int]$IntervalSeconds = 5,
    [int]$SampleCount = 60
)

$samples = for ($i = 0; $i -lt $SampleCount; $i++) {
    $process = Get-Process -Id $ProcessId -ErrorAction Stop

    [pscustomobject]@{
        Timestamp      = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
        ProcessId      = $process.Id
        WorkingSetMB   = [math]::Round($process.WorkingSet64 / 1MB, 1)
        PrivateBytesMB = [math]::Round($process.PrivateMemorySize64 / 1MB, 1)
        VirtualBytesMB = [math]::Round($process.VirtualMemorySize64 / 1MB, 1)
        Handles        = $process.HandleCount
        Threads        = $process.Threads.Count
    }

    Start-Sleep -Seconds $IntervalSeconds
}

$samples | Format-Table -AutoSize
$samples | Export-Csv .\memory-samples.csv -NoTypeInformation -Encoding utf8

.NETProcess.WorkingSet64는 Working Set, PrivateMemorySize64는 Private Bytes, VirtualMemorySize64는 Virtual Bytes에 대응합니다.141516

인스턴스가 여러 개 있는 앱에서는 이름이 아니라 PID로 추적하세요. 재시작으로 PID가 바뀌는 장기 모니터링에서는 시작 시각이나 서비스 이름 등을 기록해서 대상을 착각하지 않도록 설계해야 합니다.

9.3. PerfMon으로 시스템과 프로세스를 같은 시간축에 놓기

최소한 다음을 동시에 기록하면 원인을 가려내기 쉬워집니다.

\Process(<대상>)\ID Process
\Process(<대상>)\Working Set
\Process(<대상>)\Working Set - Private
\Process(<대상>)\Private Bytes
\Process(<대상>)\Virtual Bytes

\Memory\Available MBytes
\Memory\Committed Bytes
\Memory\Commit Limit
\Memory\Pages Input/sec
\Memory\Page Reads/sec
\Memory\Pool Nonpaged Bytes
\Memory\Pool Paged Bytes

동일한 이름의 프로세스가 여러 개 있는 경우나 모니터링 중에 재시작하는 경우, Process(name)이나 Process(name#N)이라는 인스턴스 이름만으로는 대상을 고정할 수 없습니다. 각 샘플에서 ID Process도 함께 기록하고, 그 값이 추적 대상의 PID와 일치하는 인스턴스만 채택합니다. PID가 바뀌는 재시작을 넘나드는 경우에는 전환된 시각도 별도로 기록합니다.

Windows의 성능 카운터 이름은 표시 언어에 따라 현지화되는 경우가 있습니다. PowerShell에서 영어 이름을 직접 지정했는데 찾을 수 없다면, PerfMon의 GUI에서 추가하거나 Get-Counter -ListSet *로 로컬 환경의 이름을 확인합니다.

9.4. VMMap과 RAMMap의 역할을 혼동하지 않는다

  • VMMap: 프로세스 1개의 가상 메모리와 Working Set을 Heap, Image, Mapped File, Private Data, Managed Heap 등으로 분해한다
  • RAMMap: 시스템 전체의 물리 RAM을 용도, 페이지 리스트, 프로세스, 파일별로 분해한다

「이 프로세스의 Private Bytes는 무엇 때문에 늘었는가」는 VMMap, 「프로세스 목록으로 설명되지 않는 RAM은 무엇에 사용되고 있는가」는 RAMMap입니다.1713

10. 숫자의 조합에서 증상을 읽기

관측된 형태 먼저 고려할 것 다음에 확인할 것
Working Set이 늘고 Private Bytes는 안정 기존 페이지에 대한 최초 접근, 공유 DLL, 매핑 파일, 파일 캐시 VMMap의 Image / Mapped File, Pages Input/sec
Private Bytes가 늘고 Working Set은 안정 Private한 Commit은 늘었지만 비상주이거나 Trim된 상태 VMMap의 Heap / Private Data / Managed Heap
둘 다 기동 직후에 늘고 그 후 횡보 JIT, 캐시, 풀, 초기화 워밍업 같은 부하를 추가해도 다시 늘어나는지
부하를 줄 때마다 Private Bytes의 바닥이 올라간다 누수, 상한 없는 캐시, 해제 후에도 보유하는 할당자 전후 VMMap 스냅샷, 힙 덤프
Working Set만 급격히 줄고 조작으로 돌아온다 OS 또는 앱이 Working Set을 Trim했다 Private Bytes, Pages Input/sec, 응답 시간
Committed X/Y의 X가 Y에 가까워진다 시스템 전체의 커밋 압박 Private Bytes 상위, Paged/Nonpaged Pool, 페이지 파일 설정
Available이 낮고 Pages Input/sec와 디스크 지연이 높다 물리 RAM 압박과 하드 페이징 Working Set 상위, RAMMap, 워크로드 상관관계
RAM 사용률은 높지만 큰 프로세스가 없다 캐시, 공유 페이지, 커널 풀, 드라이버, 압축 등 RAMMap, Pool Nonpaged/Paged Bytes
여유 RAM이 있는데도 32bit 앱만 실패 가상 주소 공간 상한·단편화 VMMap의 Free/Reserved, 실행 파일의 LAA 설정
Private Bytes는 높지만 처리를 반복해도 늘지 않는다 높은 수준을 유지하는 풀·캐시일 가능성 상한, 재사용 현황, 피크 이후의 안정성

이 표에서 가장 중요한 것은, 단독 값이 아니라 조합으로 읽는 것입니다.

11. 메모리 누수 조사 실무 절차

11.1. 먼저 재현 조건과 정상 상태 기준점을 정한다

「며칠 만에 늘어난다」는 것만으로는 비교할 수 없습니다.

  • 기동 후 워밍업을 어디까지 포함할 것인가
  • 1사이클의 조작 내용
  • 1사이클 후 몇 초 대기할 것인가
  • 캐시 상한에 도달하기까지 몇 번이 필요한가
  • 정상 버전·문제 버전에서 같은 입력을 사용할 수 있는가

를 정합니다.

11.2. 프로세스와 시스템을 동시에 기록한다

최소한 다음을 같은 시각에 기록해 둡니다.

  • 대상의 Working Set
  • 대상의 Private Bytes
  • 대상의 Virtual Bytes
  • 시스템의 Committed Bytes / Commit Limit
  • Available MBytes
  • Pages Input/sec
  • 핸들 수, 스레드 수
  • 조작 횟수나 처리 건수

프로세스의 Private Bytes는 안정적인데 시스템의 Commit만 늘어난다면, 다른 프로세스, 커널, 드라이버, 공유 섹션 등으로 시야를 넓힐 필요가 있습니다.

11.3. 늘어나고 있는 「차원」을 먼저 정한다

  • Working Set만: 상주 페이지, 공유·파일 유래, Trim과 재로드
  • Private Bytes: 프로세스 고유 커밋
  • Virtual Bytes만: Reserve, 매핑, 주소 공간 단편화
  • System Commit만: 다른 프로세스나 커널 쪽도 포함
  • Nonpaged Pool: 드라이버·커널 쪽
  • Handles / GDI / USER: 메모리 이외의 리소스 누수

이 순서를 건너뛰고 곧바로 덤프를 뜨면, 대상이 어긋난 채로 대량의 정보를 읽게 됩니다.

11.4. 내역 분석으로 나아간다

  • 네이티브 프로세스: VMMap, WinDbg, Application Verifier, 힙 트레이스
  • .NET: dotnet-counters, dotnet-gcdump, dotnet-dump, PerfView
  • 시스템 전체: RAMMap, PerfMon, WPR/WPA
  • 커널 풀: PoolMon, WinDbg

VMMap은 프로세스의 커밋된 가상 메모리와, 각각에 할당된 Working Set을 종류별로 표시합니다. Private Bytes의 증가를 「Heap」「Private Data」「Managed Heap」「Mapped File」중 어디까지 좁힐 수 있는지에 따라, 이후 조사 비용이 크게 달라집니다.17

11.5. 수정 후에는 같은 조건에서 기울기를 비교한다

수정 전후로 피크 값이 다르다는 것만으로는 충분하지 않습니다. 초기값이 다르면 쉽게 역전됩니다.

  • 같은 기동 상태
  • 같은 입력
  • 같은 조작 횟수
  • 같은 대기 시간
  • 같은 샘플링 간격

로 각 사이클 후의 바닥값과 기울기를 비교합니다. 누수 수정의 증명은 「최댓값이 작아졌다」가 아니라, 같은 부하를 반복해도 증가가 수렴하게 되었다는 것입니다.

12. 흔한 오해를 바로잡기

오해 1: 작업 관리자의 메모리 = 앱이 확보한 전체 양

바로잡기: 어느 열인지 확인합니다. Working Set 계열이면 현재 RAM에 상주하는 양, Commit Size 계열이면 프로세스 고유의 커밋 양입니다.

오해 2: Private Bytes = 페이지 파일 상의 바이트 수

바로잡기: Private Bytes는 Private한 Commit Charge입니다. RAM에 있는 페이지도, 필요할 때 페이지 파일로 지원되는 페이지도 포함하는 논리적인 약속량입니다.

오해 3: Commit X/Y = 페이지 파일 사용량/페이지 파일 용량

바로잡기: X는 시스템 전체의 Commit Charge, Y는 Commit Limit입니다. 페이지 파일은 Y를 확장하지만, X가 그대로 디스크 상의 사용량이 되는 것은 아닙니다.

오해 4: Page Faults/sec가 높다 = 디스크로 스왑하고 있다

바로잡기: 소프트 폴트도 포함됩니다. 디스크 I/O를 동반하는지는 Pages Input/sec나 Page Reads/sec와 디스크 지연으로 확인합니다.

오해 5: Free RAM이 적다 = 메모리 부족

바로잡기: Available, Standby, 하드 페이징, 응답 시간을 봅니다. 재사용 가능한 캐시로 RAM을 채우는 것은 정상입니다.

오해 6: Working Set을 줄일 수 있었다 = 메모리 누수를 고쳤다

바로잡기: 페이지를 RAM에서 몰아냈을 뿐일 수 있습니다. Private Bytes나 힙 안의 보유량이 줄었는지 확인합니다.

오해 7: Private Bytes가 늘었다 = 누수 확정

바로잡기: 같은 워크로드를 반복했을 때 수렴하는지, 어떤 종류의 메모리가 늘었는지, 해제 가능한 캐시인지를 확인해야 비로소 판단할 수 있습니다.

13. 정리

  • Windows의 「메모리 사용량」은 하나의 숫자가 아닙니다. 주소 공간, 커밋, RAM 상주, 공유 가능성을 나누어 생각합니다.
  • Working Set은 현재 RAM에 있는 페이지로, Private와 Shared를 모두 포함합니다. Private Working Set은 그중 프로세스 고유의 상주 페이지입니다.
  • Private Bytes는 프로세스 고유의 Commit Charge이며, 현재 RAM에 있는 양도, 페이지 파일에 실제로 기록된 양도 아닙니다.
  • Committed X/Y는 시스템 전체의 Commit Charge / Commit Limit입니다. 페이지 파일은 주로 Commit Limit, 변경된 페이지의 대피, 크래시 덤프를 지원합니다.
  • Reserve한 가상 주소, Commit한 페이지, 실제로 접근해 Working Set에 들어간 페이지는 서로 다른 단계입니다.
  • Page Fault는 통상적인 동작이며, 소프트 폴트는 디스크를 읽지 않습니다. 하드 폴트도 페이지 파일뿐만 아니라 EXE, DLL, 매핑 파일에서 발생합니다.
  • 메모리 누수는 한 시점의 크기가 아니라, 같은 부하 후의 바닥값과 기울기, 그리고 내역으로 증명합니다.
  • 개별 프로세스의 내역은 VMMap, 시스템 전체의 물리 RAM은 RAMMap, 시계열은 PerfMon, 런타임 내부는 전용 덤프 도구로 나아가는 것이 기본입니다.

다음에 작업 관리자에서 「메모리가 늘고 있다」고 눈치챘다면, 먼저 이렇게 다시 물어보세요.

늘고 있는 것은 Working Set인가, Private Bytes인가, Virtual Bytes인가, System Commit인가.

이 질문만으로도 조사의 입구는 상당히 정확해집니다.

관련 글

관련 상담 영역

합동회사 코무라소프트에서는 Windows 앱의 메모리 증가, 장기 가동 후 성능 저하, 32bit 프로세스의 OutOfMemory, 고객 환경에서만 발생하는 메모리 부족에 대해, PerfMon·VMMap·RAMMap·WinDbg·.NET 진단 도구를 조합한 원인 조사를 다루고 있습니다. 단순히 「메모리가 많다」로 끝내지 않고, 어느 영역이, 어떤 조작으로, 왜 늘어났으며, 어디서 참조·보유되고 있는지까지 가려냅니다.

참고 링크

  1. Microsoft Learn, Working Set. 프로세스의 Working Set이 현재 물리 메모리에 상주하는 페이지의 집합이라는 점, 공유 페이지를 포함한다는 점, 소프트·하드 페이지 폴트의 차이, Transition 페이지, Working Set에서의 페이지 제거에 대해.  2 3 4 5

  2. Microsoft Learn, PROCESS_MEMORY_COUNTERS_EX2 structure. WorkingSetSize, PrivateWorkingSetSize, PrivateUsage, SharedCommitUsage의 정의, PagefileUsage와 PrivateUsage가 모두 프로세스의 Commit Charge를 나타낸다는 점에 대해.  2 3 4

  3. Microsoft Learn, Introduction to page files. 페이지 파일이 변경된 페이지의 대피, 시스템 크래시 덤프, System Commit Limit의 확장을 지원한다는 점, System Commit Charge와 Commit Limit의 정의, 작업 관리자 및 성능 카운터를 이용한 측정에 대해.  2 3 4

  4. Microsoft Learn, Page State. 가상 페이지의 Free, Reserved, Committed 각 상태와, Reserved 페이지에는 물리 스토리지가 연결되지 않아 접근할 수 없다는 점에 대해.  2

  5. Microsoft Learn, VirtualAlloc function. MEM_RESERVE와 MEM_COMMIT의 차이, Commit 시 시스템 전체의 메모리와 페이지 파일에서 Charge된다는 점, 실제 물리 페이지는 최초 접근까지 할당되지 않는 경우가 있다는 점에 대해.  2 3

  6. Microsoft Learn, How to determine the appropriate page file size for 64-bit versions of Windows. 페이지 파일의 크기가 피크 Commit Charge와 크래시 덤프 요건에 좌우된다는 점, 하드 페이지 폴트가 읽어 오는 곳이 페이지 파일에 국한되지 않고 EXE·DLL·메모리 매핑 파일을 포함한다는 점, 관련 성능 카운터에 대해.  2 3 4 5 6

  7. Microsoft Learn, Virtual Address Space. 각 프로세스가 독립된 가상 주소 공간과 페이지 테이블을 가지며, 가상 주소가 물리 주소 그 자체는 아니라는 점에 대해. 

  8. Microsoft Learn, Memory Limits for Windows and Windows Server Releases. 32bit 프로세스의 사용자 모드 가상 주소 공간이 보통 2GB이며, 64bit Windows에서는 IMAGE_FILE_LARGE_ADDRESS_AWARE의 유무에 따라 2GB 또는 4GB가 된다는 점에 대해. 

  9. Microsoft Learn, SetProcessWorkingSetSize function. Working Set의 최소·최대값이 상주를 보장하는 것은 아니라는 점, Working Set을 비울 수 있다는 점, 과도한 설정이나 조작이 시스템 성능을 악화시킬 수 있다는 점에 대해. 

  10. Microsoft Learn, Memory Performance Information. Windows의 성능 카운터, 메모리 관리 API, 작업 관리자 표시 간의 대응 관계, Process의 Working Set·Working Set - Private·Private Bytes, System의 Committed Bytes·Commit Limit에 대해. 

  11. Microsoft Learn, MapViewOfFile function. FILE_MAP_COPY에서는 모든 페이지가 Copy-on-write가 될 수 있기 때문에, 뷰 전체를 페이지 파일로 뒷받침할 수 있도록 매핑 시점에 Commit Charge가 확보된다는 점에 대해. 

  12. Microsoft Learn, Understanding Node Metrics and Properties in HPC Cluster Manager. Available Physical Memory가 Zeroed, Free, Standby 각 리스트의 합계로 계산된다는 점과, 각 페이지 리스트의 의미에 대해. 

  13. Microsoft Sysinternals, RAMMap. Windows의 물리 메모리 사용량을 용도, 페이지 리스트, 프로세스, 우선순위, 물리 페이지, 파일 단위로 분석하는 기능에 대해.  2

  14. Microsoft Learn, Process.WorkingSet64 Property. WorkingSet64가 프로세스의 Working Set을 바이트 단위로 반환하며, Process의 Working Set 성능 카운터에 대응한다는 점에 대해. 

  15. Microsoft Learn, Process.PrivateMemorySize64 Property. PrivateMemorySize64가 다른 프로세스와 공유할 수 없는 프로세스 고유 메모리를 반환하며, Private Bytes 성능 카운터에 대응한다는 점에 대해. 

  16. Microsoft Learn, Process.VirtualMemorySize64 Property. VirtualMemorySize64가 프로세스의 가상 메모리량을 반환하며, Virtual Bytes 성능 카운터에 대응한다는 점에 대해. 

  17. Microsoft Sysinternals, VMMap. 프로세스의 커밋된 가상 메모리를 종류별로 분해하고, 각각에 할당된 물리 메모리(Working Set)와 상세한 메모리 맵을 표시하는 기능에 대해.  2

같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.

이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.

이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.

자주 묻는 질문

이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.

작업 관리자의 「메모리」는 앱이 확보한 전체 메모리인가요?
아닙니다. 작업 관리자에는 Working Set 계열, Private Working Set 계열, Commit Size 등 여러 메모리 열이 있으며, 어느 화면·열을 보는지에 따라 의미가 달라집니다. Working Set은 현재 RAM에 올라와 있는 페이지, Private Bytes 또는 Commit Size는 그 프로세스 고유의 커밋 양입니다. 하나의 「메모리」열을 앱이 확보한 전체 용량이나 누수 양으로 바꿔 읽지 마세요.
Working Set과 Private Bytes는 무엇이 다른가요?
Working Set은 그 프로세스에서 볼 수 있으며 현재 물리 RAM에 상주하고 있는 페이지의 양으로, DLL이나 메모리 매핑 파일 등의 공유 페이지도 포함합니다. Private Bytes는 그 프로세스만 사용하는 커밋된 메모리의 양으로, 현재 RAM에 상주하고 있는지 여부는 따지지 않습니다. 따라서 두 값은 같은 값이 되지 않으며, 단순한 대소 관계도 아닙니다.
작업 관리자의 「커밋됨 18/32GB」는 18GB를 페이지 파일에 기록하고 있다는 의미인가요?
아닙니다. 왼쪽 숫자는 시스템 전체가 현재 약속하고 있는 커밋 양, 오른쪽 숫자는 시스템이 지원할 수 있는 커밋 상한입니다. 상한은 대체로 RAM과 페이지 파일의 합계로 결정되지만, 왼쪽의 전체 양이 페이지 파일 상에 있는 것은 아닙니다. 커밋된 페이지 중 상당수는 RAM에 있으며, 아직 한 번도 물리 페이지가 할당되지 않은 페이지도 있습니다. 한편 EXE·DLL·메모리 매핑 파일처럼 원본 파일에서 다시 읽어 올 수 있는 페이지는, Working Set을 늘려도 Private한 Commit을 그만큼 늘린다고는 할 수 없습니다.
여유 RAM이 있는데도 OutOfMemory가 발생할 수 있나요?
있습니다. 32bit 프로세스의 가상 주소 공간 부족, 연속된 여유 주소 범위의 부족, 시스템의 커밋 상한, Job Object나 런타임 고유의 상한 등, 물리 RAM 이외에도 할당 실패의 조건이 있기 때문입니다. 특히 64bit Windows 상의 32bit 프로세스는 Large Address Aware가 아니면 보통 2GB의 사용자 모드 가상 주소 공간이 상한입니다.
페이지 파일을 비활성화하면 Windows가 빨라지나요?
일반적으로는 빨라진다고 단정할 수 없습니다. 페이지 파일을 비활성화하면 시스템의 커밋 상한이 낮아지고, 사용되지 않는 변경된 페이지를 RAM에서 대피시키기 어려워지며, 크래시 덤프의 구성에도 영향을 줍니다. 페이지 파일의 크기는 피크 시의 커밋 양과 필요한 크래시 덤프를 측정한 뒤에 결정해야 하며, 근거 없이 비활성화할 설정이 아닙니다.
Page Faults/sec가 많으면 메모리 부족인가요?
그것만으로는 판단할 수 없습니다. 페이지 폴트에는 RAM 내의 Standby 페이지나 다른 프로세스와 공유 중인 페이지로 해결할 수 있는 소프트 폴트와, 디스크에서 읽어 오는 하드 폴트가 있습니다. Page Faults/sec 단독이 아니라 Pages Input/sec나 Page Reads/sec, Available MBytes, 디스크 지연, 처리 시간을 같은 시간축에서 함께 확인하세요.

저자 프로필

기사 저자의 프로필 페이지입니다.

Go Komura

합동회사 코무라소프트 대표

Windows 소프트웨어 개발, 기술 상담, 장애 조사를 중심으로 재현이 어려운 장애 조사와 기존 자산이 남아 있는 프로젝트에 강점이 있습니다.

블로그 목록으로 돌아가기