Windows 11 메모리 누수 원인 추적과 완벽 해결 가이드

이 글의 목적은 Windows 11 환경에서 발생하는 메모리 누수를 신속하고 체계적으로 진단하여 재발 없이 해결할 수 있도록 현업 엔지니어 수준의 절차와 도구 사용법을 제공하는 것이다.

1. 메모리 누수를 올바르게 정의하고 구분하기

메모리 누수는 프로세스가 확보한 메모리를 필요 이상으로 오래 유지하거나 해제하지 않아 시스템 가용 메모리가 지속적으로 감소하는 현상을 의미한다. 단기적인 캐시 증가나 일시적 워킹셋 확장은 누수와 다르다. 진단의 첫 단계는 다음 세 가지 현상을 구분하는 것이다.

현상핵심 지표설명조치 우선순위
실제 누수Private Bytes 지속 상승, Handle/객체 증가해제되지 않는 힙·핸들·커널 풀 소비로 가용 메모리가 회복되지 않는다.매우 높다
캐시 증가Standby/Modified 증가, 프로세스 종료 시 회복파일 캐시·메모리 압축 등 정상 동작으로 부하 종료 시 자동 회복된다.중간
워킹셋 팽창Working Set 급증·급감 반복I/O 집중·탭 많은 브라우저 등에서 순간적으로 페이지인이 증가한다.낮다
주의 : “메모리 사용량이 높다” 만으로 누수라고 단정하지 않는다. 시간 축에서의 일관된 증가복구 실패가 핵심 판단 기준이다.

2. 10분 만에 끝내는 1차 진단(관리자 권한 불필요)

  1. 작업 관리자를 열어 프로세스 정렬 기준을 “메모리”와 “메모리 구성요소 > 커밋(Commit)”으로 번갈아 확인한다. 특정 프로세스의 값이 시간 경과에 따라 계속 상승하는지 관찰한다.
  2. 리소스 모니터에서 “메모리 > 커밋(최대)/하드 폴트/스탠바이”를 확인하여 파일 캐시 증가인지 프로세스 전용 커밋 증가인지 구분한다.
  3. 이벤트 뷰어에서 “진단-성능”과 “리소스-소진” 로그를 확인한다. Event ID 2004가 연속 발생하면 누수 가능성이 높다.
eventvwr.msc # Windows 로그 > 시스템 > 리소스-소진 진단 

3. 24시간 추적용 자동 로깅 스크립트(경량 수집)

수동 관찰의 한계를 보완하기 위해 1~5분 주기로 핵심 카운터를 기록한다. 다음 PowerShell 스크립트는 Private Bytes, Working Set, Handle 수를 CSV로 저장하여 나중에 누수 패턴을 시계열로 분석하게 해준다.

# save as Track-Memory.ps1, 관리자 권한 불필요 param( [int]$IntervalSec = 60, [int]$Samples = 1440, # 24h [string]$OutPath = "$env:USERPROFILE\Desktop\memlog.csv" ) "Timestamp,PID,Name,PrivateBytes,WorkingSet,Handles,CommitTotal,CommitLimit,NonPaged,Paged" | Out-File -Encoding utf8 $OutPath for ($i=0; $i -lt $Samples; $i++) { $procs = Get-Process | Select-Object Id, ProcessName, PrivateMemorySize64, WorkingSet64, Handles $os = Get-CimInstance Win32_OperatingSystem $mem = Get-Counter -Counter "\Memory\Committed Bytes","\Memory\Commit Limit","\Memory\Pool Nonpaged Bytes","\Memory\Pool Paged Bytes" $cb = [int64]$mem.CounterSamples | Where-Object {$_.Path -like "*Committed Bytes*"} | Select-Object -ExpandProperty CookedValue $cl = [int64]$mem.CounterSamples | Where-Object {$_.Path -like "*Commit Limit*"} | Select-Object -ExpandProperty CookedValue $np = [int64]$mem.CounterSamples | Where-Object {$_.Path -like "*Nonpaged*"} | Select-Object -ExpandProperty CookedValue $pp = [int64]$mem.CounterSamples | Where-Object {$_.Path -like "*Paged Bytes*"} | Select-Object -ExpandProperty CookedValue $ts = (Get-Date).ToString("s") foreach ($p in $procs) { "$ts,$($p.Id),$($p.ProcessName),$($p.PrivateMemorySize64),$($p.WorkingSet64),$($p.Handles),$cb,$cl,$np,$pp" | Add-Content -Encoding utf8 $OutPath } Start-Sleep -Seconds $IntervalSec } 

기록 후 Excel이나 데이터 분석 도구로 PID별 PrivateBytes와 Handles의 단조 증가를 확인한다.

4. 성능 카운터 기반 정량 진단(PerfMon)

다음 카운터를 1~5초 샘플링으로 추가하여 Data Collector Set을 구성한다.

카운터 경로설명누수 시 징후
Process\Private Bytes(_Total 및 의심 PID)프로세스 전용 커밋지속 상승 후 하락 없음
Process\Handle Count(의심 PID)핸들 누수 탐지선형 증가
.NET CLR Memory\# Bytes in all Heaps(의심 .NET)관리 힙 크기Gen2 증가·GC 후에도 회복 없음
Memory\Pool Nonpaged Bytes커널 비페이지드 풀재부팅 전까지 지속 상승
Memory\Committed Bytes / Commit Limit시스템 커밋 압박Committed Bytes가 Limit 근접
perfmon.exe # Performance Monitor > Data Collector Sets > User Defined > New > Data Collector Set 
주의 : Committed Bytes가 Commit Limit의 80%를 초과하면 사용자 체감 성능 저하와 함께 OOM 오류 가능성이 높아지므로 즉시 원인 프로세스를 종료하거나 메모리 덤프를 채취한다.

5. 사용자 모드 누수 분석: WPR/WPA와 UMDH

5.1 Windows Performance Recorder/Analyzer

  1. WPR을 관리자 권한으로 실행하여 “Resource Analysis” 또는 “Memory” 프로필을 선택한다.
  2. 문제가 재현되는 동안 1~5분 추적 후 중지한다.
  3. WPA에서 “Process Memory”, “VirtualAlloc” 스택을 분석하여 누수 의심 할당 스택을 찾는다.
# 관리자 PowerShell wpr -start GeneralProfile -filemode # 재현 후 wpr -stop "$env:USERPROFILE\Desktop\leak.etl" 

5.2 UMDH(사용자 모드 힙 덤프 비교)

  1. Debugging Tools for Windows 설치 후 gflags로 UST(사용자 스택 추적) 활성화한다.
  2. 의심 프로세스 시작 → umdh로 스냅샷 A 저장 → 5~10분 후 스냅샷 B 저장 → 델타 비교한다.
# 관리자 CMD gflags /i target.exe +ust umdh -p:<PID> -f:snapA.txt timeout /t 600 umdh -p:<PID> -f:snapB.txt umdh snapA.txt snapB.txt > delta.txt 

delta.txt에서 특정 모듈·함수 스택이 큰 양수 증가를 보이면 누수 원인 코드 경로이다.

주의 : UST는 오버헤드를 증가시킨다. 분석 후 gflags /i target.exe -ust로 반드시 되돌린다.

6. 커널 메모리 누수 분석: PoolMon과 RamMap

6.1 PoolMon으로 태그 기반 추적

  1. 관리자 CMD에서 poolmon -b 실행 후 NonpPaged 또는 Paged 정렬로 증가하는 태그를 식별한다.
  2. 증가 태그를 드라이버/모듈과 매핑하여 업데이트 또는 제거 조치를 수행한다.
# 관리자 CMD poolmon -b # B 키로 정렬 변경, P/N로 풀 선택, 증가 추세 태그 기록 

6.2 RamMap으로 시스템 뷰 확보

RamMap에서 “Use Counts > Nonpaged Pool / Paged Pool / File Summary”를 확인하여 파일 캐시와 커널 풀이 구분된다. 커널 풀이 지배적이면 드라이버 문제 가능성이 높다.

7. 누수 유형별 원인 매트릭스와 해결책

유형징후주요 원인해결 절차
사용자 모드 힙 누수 Private Bytes 상승, Handles 동반 상승 버그 있는 앱·브라우저 확장·백그라운드 유틸 WPR/WPA 또는 UMDH로 스택 식별 → 앱 업데이트·삭제 → 대체 앱 전환
.NET 관리 힙 누수 CLR Heaps 증가, Gen2 GC 후에도 회복 없음 이벤트 핸들러 Detach 누락, Static 참조 유지 PerfMon CLR 카운터 분석 → 개발사 패치 요청 또는 버전 롤백
핸들 누수 Handle Count 선형 증가 파일/레지스트리/그DI/소켓 핸들 미해제 Handle 추적 도구/UMDH로 핸들 타입 식별 → 문제 모듈 교체
커널 풀 누수 Nonpaged Pool 지속 증가, 시스템 전역 영향 오작동 드라이버, 보안/가상화 필터 PoolMon 태그 매핑 → 드라이버 업데이트·제거 → 필요 시 베어메탈 클린 부팅 검증
파일 캐시 과대 Standby/Modified 큼, 프로세스 종료 시 회복 대용량 I/O, 백업/동기화 작업 스케줄 조정, 제외 경로 설정, 캐시 영향 이해

8. 안전한 재현 환경 만들기(클린 부팅·격리)

  1. 클린 부팅: MS 서비스 외 비활성화, 시작 프로그램 최소화로 재현한다.
  2. 사용자 계정 분리: 새 로컬 프로필에서 재현하여 프로필 손상 여부를 배제한다.
  3. 오프라인 격리: 네트워크 차단 상태에서 재현하여 동기화/클라우드 영향 배제한다.
msconfig # 서비스 탭: '모든 Microsoft 서비스 숨기기' 체크 후 모두 사용 안 함 
주의 : 업무 단절 위험이 있으므로 클린 부팅 전 변경 항목을 기록하고, 복귀 체크리스트를 준비한다.

9. 즉각적인 완화 조치(서비스 지속을 위한 단기 대응)

  • 의심 프로세스 주기 재시작: 작업 스케줄러로 비업무 시간대에 종료·재시작하여 누적 누수를 초기화한다.
  • Commit Margin 확보: 페이지 파일을 시스템 관리 크기로 설정하여 커밋 한도를 충분히 유지한다.
  • 메모리 덤프 자동 채취: 임계치 도달 시 Procdump로 자동 덤프를 저장한다.
# 관리자 CMD, 커밋 압박 시 3회 덤프 procdump -ma -i C:\Dumps procdump -ma -s 5 -n 3 <PID> C:\Dumps 
주의 : 덤프에는 민감 데이터가 포함될 수 있다. 사내 보안 정책에 따라 암호화 저장·열람 권한을 제한한다.

10. 재발 방지 운영 표준(OSP) 수립

  1. 변경관리: 드라이버·에이전트·확장 프로그램 배포 전 표준 이미지에서 24시간 soak 테스트를 의무화한다.
  2. 관측성: PerfMon DCS와 PowerShell 로깅을 상시 운영하고 7~14일 보존한다.
  3. 취약 구성 제거: 불필요한 쉘 확장·프린터 필터·네트워크 필터를 주기적으로 감축한다.
  4. 패치 링: 업데이트를 Pilot→Broad 2단계로 순차 적용한다.

11. 현장에서 바로 쓰는 체크리스트

#점검 항목도구합격 기준
1의심 PID의 Private Bytes 단조 증가 확인Task Manager, PerfMon증가율 0에 수렴 또는 작업 종료 시 회복
2Handle Count 선형 증가 여부PerfMon증가율 안정화
3커널 Nonpaged Pool 증가PerfMon, RamMap부하 종료 후 안정
4이벤트 2004·리소스 소진 알림Event Viewer연속 미발생
5WPR/WPA 스택에서 반복 할당 발견WPR/WPA문제 스택 식별·조치
6PoolMon 태그 매핑 완료PoolMon문제 드라이버 업데이트 또는 제거
7페이지 파일 구성 최적화시스템 설정시스템 관리 크기 또는 충분한 커밋 여유

12. 페이지 파일과 메모리 압축 이해

Windows 11은 메모리 압축을 통해 워킹셋을 줄이며 커밋 사용량은 변하지 않는다. 커밋 고갈은 페이지 파일 용량과 직결되므로 서버·워크스테이션 모두에서 시스템 관리 크기를 권장한다. SSD 환경에서 페이지 파일 사용은 현대적인 스케줄러와 wear leveling으로 일반적인 사용 수명에 큰 영향을 주지 않는다.

13. 드라이버·보안/가상화 필터 최적화

네트워크·스토리지·프린터·보안 필터 드라이버는 커널 풀을 소비한다. 배포 전 테스트 링에서 다음을 확인한다.

  • 대량 I/O 시 Nonpaged Pool 증가가 부하 종료 후 안정화되는지 확인한다.
  • 필요 없는 패킷 검사·DLP 모듈은 정책에 맞춰 비활성화한다.
  • WSL, 가상 머신 플랫폼, 하이퍼바이저 기능은 사용 환경에서만 활성화한다.

14. 브라우저·탭 다중 환경 최적화

멀티 프로세스 브라우저는 탭마다 프로세스를 생성하며 확장 프로그램은 장시간 실행 시 누수의 핵심 원인이 될 수 있다. 다음을 권장한다.

  1. 확장 프로그램을 1개씩 비활성화하며 재현한다.
  2. 프로파일을 새로 만들어 테스트한다.
  3. 미디어/개발자 도구 사용 탭은 별도 프로필로 분리한다.

15. 자동 복구 시나리오 설계

업무 연속성이 중요한 PC는 다음 스크립트로 임계치 기반 자동 종료·재시작을 구성한다.

# Kill-If-Leaking.ps1 param([int]$Pid,[int64]$ThresholdMB=2048) while ($true) { try { $p = Get-Process -Id $Pid -ErrorAction Stop $mb = [math]::Round($p.PrivateMemorySize64/1MB) if ($mb -gt $ThresholdMB) { Stop-Process -Id $Pid -Force Start-Sleep -Seconds 5 Start-Process -FilePath $p.Path } } catch { break } Start-Sleep -Seconds 60 } 
주의 : 강제 종료는 데이터 손실을 유발할 수 있다. 백업·자동 저장 정책을 먼저 검토한다.

16. 사례 기반 원인-해결 매핑 예시

  • 클라우드 동기화 도구: 대량 소규모 파일 처리 후 Standby 증가 및 워킹셋 팽창이 관찰되나 부하 종료 시 회복된다. 스로틀링 또는 제외 경로 설정으로 개선한다.
  • 인쇄 스풀러 확장: 대기열 대량 처리 시 Nonpaged Pool 증가와 함께 시스템 전체 지연이 발생한다. 필터 드라이버 업데이트로 해결한다.
  • 보안 에이전트: 핸들 누수로 Private Bytes보다 Handle Count가 더 일관되게 상승한다. 정책 조정 또는 에이전트 버전 교체로 해결한다.

17. 보고서 양식(현장 적용 템플릿)

# 메모리 누수 분석 보고서 템플릿
환경정보

OS/빌드:

메모리/페이지 파일:

보안/가상화/필터:

현상 요약

발생 시각/주기:

사용자 체감 증상:

정량 지표

Committed Bytes/Limit:

의심 PID PrivateBytes/Handles 추이:

추적/분석

PerfMon DCS 설정:

WPR/WPA 결과 핵심 스택:

PoolMon 태그 > 드라이버 매핑:

조치

단기: 재시작/스로틀/정책

영구: 패치/드라이버 교체/구성 변경

재발 방지

모니터링/패치 링/변경관리 계획

18. 최종 체크포인트

  1. Private Bytes 또는 Nonpaged Pool이 시간 축에서 상승만 하는지 확인했다.
  2. 핵심 지표를 CSV·ETL로 저장했다.
  3. WPR/WPA 또는 UMDH/PoolMon으로 스택/태그를 확보했다.
  4. 원인 모듈을 업데이트·제거했다.
  5. 페이지 파일과 로깅을 상시화했다.

FAQ

메모리 압축을 끄면 문제가 해결되나?

권장하지 않는다. 압축은 커밋 한도를 늘리지 않지만 워킹셋 압박을 줄여 체감 성능을 개선한다. 누수 해결은 압축 비활성화가 아니라 원인 모듈 식별과 수정에 달려 있다.

페이지 파일을 없애면 빠르다던데 사실인가?

아니다. 커밋 한도가 급격히 낮아져 OOM과 크래시 위험이 커진다. SSD 환경에서는 적정한 페이지 파일이 안정성과 성능 모두에 유리하다.

누수 의심 프로세스를 종료하면 항상 안전한가?

아니다. 데이터 손실 가능성이 있다. 종료 전에 저장·백업·덤프 채취를 고려하고 비업무 시간에 자동 재시작을 설계한다.

드라이버가 원인인지 어떻게 확정하나?

Nonpaged Pool 증가와 PoolMon 태그를 드라이버와 매핑하여 증거를 확보한다. 해당 드라이버 업데이트 또는 제거 후 동일 부하 재현으로 검증한다.

브라우저 탭이 많으면 항상 누수인가?

아니다. 탭 수에 비례해 메모리 사용이 증가하는 것은 설계 특성이다. 누수는 탭을 닫아도 메모리가 회복되지 않거나 장시간 단조 증가가 지속될 때 의심한다.