WSL2 메모리 최적화 완벽 가이드 - 32GB 시스템에서 뻗지 않는 개발환경 만들기
WSL2 메모리 최적화 완벽 가이드
프롤로그: 15.9GB를 찍고 뻗어버린 날
AI 코딩 도구(opencode)를 3개 동시에 돌리면서 빌드까지 트리거했더니, vmmem 프로세스가 15.9GB를 잡아먹고 컴퓨터 전체가 뻗어버렸습니다. 팬 소음은 비행기 이륙 수준, 마우스 커서는 1초에 한 번 깜빡…
32GB 시스템인데도 이런 일이 벌어진 이유와, 실제로 해결한 전 과정을 공유합니다.
이 글의 모든 설정은 실제 적용 후 검증한 것입니다. 복사해서 바로 쓸 수 있습니다.
1단계: 문제 진단
왜 터졌나?
WSL2는 기본적으로 **시스템 RAM의 50%**를 가져갑니다. 32GB 시스템이면 16GB. 여기에:
| 항목 | 메모리 |
|---|---|
| AI 코딩 도구 × 3개 | ~4.5GB |
| MCP 서버 (Node.js) × 9개 | ~2.7GB |
| 리눅스 커널 + 서비스 | ~1GB |
| 페이지 캐시 (파일 캐시) | ~2GB |
| 빌드 프로세스 (npm/webpack/tsc) | +2~4GB |
| 총합 | 12~14GB |
핵심 문제: WSL2는 한번 잡은 메모리를 자발적으로 잘 안 놓아줍니다.
진단 명령어
# WSL 내부에서 메모리 상태 확인free -h
# 메모리 많이 먹는 프로세스 확인ps aux --sort=-%mem | head -20
# 스왑 상태swapon --show2단계: Windows 쪽 설정 (.wslconfig)
가장 중요한 설정입니다. 이 파일이 WSL2 VM의 리소스 상한을 결정합니다.
파일 위치
C:\Users\{사용자이름}\.wslconfig권장 설정 (32GB 시스템 기준)
[wsl2]memory=12GBswap=4GBlocalhostForwarding=truenestedVirtualization=falseguiApplications=true
[experimental]# ⚠️ 가장 중요한 설정!# 미사용 메모리를 즉시 Windows에 반환autoMemoryReclaim=dropCache
# 데이터 손상 버그로 Microsoft가 내부적으로 비활성화함# 절대 true로 설정하지 마세요 (GitHub Issue #12103)sparseVhd=falseautoMemoryReclaim 옵션 비교
| 모드 | 동작 | 권장 여부 |
|---|---|---|
dropCache | 캐시 메모리 즉시 반환 | ✅ 권장 (2024.05부터 기본값) |
gradual | 5분 idle 후 천천히 반환 | ❌ Docker/systemd 충돌 버그 |
disabled | 반환 안 함 | ❌ |
⚠️ gradual을 쓰면 안 되는 이유
- Docker Desktop의 Resource Saver 모드와 충돌하여 WSL이 멈춤 (GitHub #11066)
- systemd 활성화 상태에서 명령어가 행 (GitHub #10675)
설정 적용
# PowerShell (관리자 권한)wsl --shutdown# 이후 WSL 다시 시작12GB가 합리적인 이유
autoMemoryReclaim=dropCache와 함께 사용하면 memory 값은 **“예약”이 아니라 “천장”**입니다:
- WSL이 6GB만 쓰면 → 나머지 6GB는 Windows에 즉시 반환
- WSL이 12GB까지 필요하면 → 12GB까지 사용 가능
- Windows에는 항상 20GB+ 여유 유지
3단계: zram 활성화 (압축 스왑)
zram은 메모리의 일부를 압축해서 실질적으로 사용 가능한 메모리를 늘려줍니다.
설치 및 활성화
# zram-config 설치sudo apt update && sudo apt install -y zram-config
# 서비스 시작sudo systemctl start zram-configsudo systemctl enable zram-config
# 확인zramctl확인 결과 예시
NAME ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT/dev/zram0 lzo-rle 5.8G 4K 75B 12K 12 [SWAP]12GB 중 약 5.8GB의 압축 스왑이 추가됩니다. lzo-rle 알고리즘으로 23배 압축되므로, 실질적으로 메모리가 1517GB인 것처럼 동작합니다.
4단계: sysctl 커널 튜닝
리눅스 커널의 메모리 관리 방식을 WSL2에 맞게 최적화합니다.
설정 파일 생성
sudo tee /etc/sysctl.d/99-wsl2-tuning.conf > /dev/null << 'EOF'#################################################################### WSL2 Memory Optimization (Research-backed, 2025)# Sources: Microsoft Learn, GitHub microsoft/WSL, Whitewater Foundry###################################################################
# zram 사용시 100이 최적 (150+는 zswap 전용)vm.swappiness=100
# WSL2는 9P/virtiofs 오버헤드가 크므로 캐시 유지가 중요# 50 = 캐시를 적당히 유지하면서 메모리도 확보vm.vfs_cache_pressure=50
# dirty page 비율 낮춰서 메모리 점유 최소화vm.dirty_ratio=10vm.dirty_background_ratio=5
# 최소 free 메모리 확보 (128MB)vm.min_free_kbytes=131072
# 워터마크 조정vm.watermark_boost_factor=0vm.watermark_scale_factor=125
# proactive memory compactionvm.compaction_proactiveness=50
# 대규모 프로젝트 파일 워치 수fs.inotify.max_user_watches=524288EOF즉시 적용
sudo sysctl --system각 설정값의 의미
| 파라미터 | 기본값 | 설정값 | 이유 |
|---|---|---|---|
vm.swappiness | 60 | 100 | zram이 있으므로 적극적으로 압축 스왑 활용 |
vm.vfs_cache_pressure | 100 | 50 | WSL2의 파일시스템(9P)은 캐시 의존도가 높음. 너무 날리면 느려짐 |
vm.dirty_ratio | 20 | 10 | 쓰기 대기 메모리를 줄여서 메모리 압박 감소 |
vm.min_free_kbytes | 자동 | 131072 | 128MB를 항상 비워두어 OOM 방지 |
fs.inotify.max_user_watches | 8192 | 524288 | VS Code, webpack 등의 파일 워치 한도 확대 |
⚠️ swappiness 주의사항
- zram 없이: 10~20 권장
- zram 사용시: 100 권장
- zswap 사용시: 133 권장 (커스텀 커널 필요)
- 150 이상은 zswap 전용이며, zram에서는 효과 없음
5단계: 자동 캐시 드롭 타이머
WSL2는 페이지 캐시를 쌓아두고 잘 안 놓아줍니다. 주기적으로 비워주면 Windows에 메모리가 반환됩니다.
스크립트 생성
sudo tee /usr/local/bin/wsl2-drop-cache << 'SCRIPT'#!/bin/bash# WSL2 Cache Drop - idle 상태에서만 실행LOAD=$(awk '{print $1}' /proc/loadavg)THRESHOLD="1.0"
if (( $(echo "$LOAD < $THRESHOLD" | bc -l 2>/dev/null || echo 0) )); then sync echo 3 > /proc/sys/vm/drop_caches logger "WSL2: Cache dropped (load: $LOAD)"fiSCRIPTsudo chmod +x /usr/local/bin/wsl2-drop-cachesystemd 타이머 설정 (5분마다)
# 서비스 파일sudo tee /etc/systemd/system/wsl2-drop-cache.service > /dev/null << 'EOF'[Unit]Description=WSL2 Drop Cache When Idle
[Service]Type=oneshotExecStart=/usr/local/bin/wsl2-drop-cacheEOF
# 타이머 파일sudo tee /etc/systemd/system/wsl2-drop-cache.timer > /dev/null << 'EOF'[Unit]Description=WSL2 Cache Drop Timer (every 5 min)
[Timer]OnBootSec=2minOnUnitActiveSec=5minPersistent=true
[Install]WantedBy=timers.targetEOF
# 활성화sudo systemctl daemon-reloadsudo systemctl enable --now wsl2-drop-cache.timer6단계: earlyoom (OOM 크래시 방지)
이것이 가장 중요한 안전장치입니다. 메모리가 바닥나기 전에 빌드 프로세스를 안전하게 종료합니다.
earlyoom 없이 메모리가 부족하면?
- 리눅스 OOM Killer가 아무 프로세스나 죽임
- 또는 WSL2 VM 전체가 뻗음
- Windows까지 먹통 → 강제 재부팅
earlyoom이 있으면?
- 메모리 8% 이하 → 경고 로그
- 메모리 5% 이하 → 빌드 프로세스(npm, webpack, tsc)를 먼저 킬
- WSL2와 Windows는 안전하게 유지
설치 및 설정
sudo apt install -y earlyoom# 설정 파일sudo tee /etc/default/earlyoom > /dev/null << 'EOF'# -m: 메모리 경고%/킬%# -s: 스왑 경고%/킬%# --avoid: 이 프로세스는 보호 (최후에 킬)# --prefer: 이 프로세스를 먼저 킬EARLYOOM_ARGS="-m 8,5 -s 5,3 --avoid '(^|/)(init|sshd|systemd|tailscaled)$' --prefer '(^|/)(npm|npx|webpack|vite|esbuild|tsc|jest)$' -n"EOF
sudo systemctl restart earlyoom핵심: --prefer로 일회성 빌드 프로세스를 먼저 킬하고, --avoid로 시스템 프로세스는 보호합니다.
7단계: 불필요 서비스/패키지 정리
WSL2에는 Ubuntu 서버용 패키지가 기본 설치되어 있습니다. 개발환경에서 필요 없는 것들이 많습니다.
비활성화할 서비스
# 클라우드 VM 전용 (WSL 아님)sudo systemctl disable --now cloud-init.service cloud-init-local.service \ cloud-config.service cloud-final.service
# Snap (설치된 앱 없으면 불필요)sudo systemctl disable --now snapd.service snapd.socket snapd.seeded.service \ snapd.apparmor.service snapd.autoimport.service snapd.core-fixup.service
# 기타 불필요sudo systemctl disable --now landscape-client.service # Canonical 관리 도구sudo systemctl disable --now ufw.service # Windows 방화벽이 처리sudo systemctl disable --now irqbalance.service # 가상머신이라 무의미sudo systemctl disable --now rsyslog.service # journald와 중복sudo systemctl disable --now apparmor.service # 개발환경 불필요sudo systemctl disable --now ua-reboot-cmds.service ubuntu-advantage.service
# packagekit (apt 자동 업데이트 GUI)sudo systemctl disable --now packagekit.servicesudo systemctl mask packagekit.service제거할 패키지
# snap (설치된 앱이 없다면)sudo apt purge -y snapd
# 음성인식 라이브러리 (??)sudo apt purge -y pocketsphinx-en-us libpocketsphinx3
# cloud-initsudo apt purge -y cloud-init cloud-guest-utils
# landscapesudo apt purge -y landscape-client landscape-common
# 고아 패키지 정리sudo apt autoremove -y
# apt 캐시 정리sudo apt cleanjournald 로그 크기 제한
sudo mkdir -p /etc/systemd/journald.conf.dsudo tee /etc/systemd/journald.conf.d/size-limit.conf > /dev/null << 'EOF'[Journal]SystemMaxUse=100MRuntimeMaxUse=50MEOFsudo systemctl restart systemd-journald8단계: 앱 레벨 메모리 제한
Node.js와 Java는 기본적으로 메모리를 많이 씁니다. 상한을 걸어줍니다.
~/.bashrc에 추가
# Node.js: 프로세스당 최대 힙 2GBexport NODE_OPTIONS="--max-old-space-size=2048"
# Javaexport JAVA_OPTS="-Xmx2g -XX:+UseG1GC -XX:+UseContainerSupport"export MAVEN_OPTS="-Xmx1g"export GRADLE_OPTS="-Xmx1g"최종 점검 스크립트
모든 설정이 제대로 적용되었는지 한번에 확인하는 스크립트입니다.
#!/bin/bashecho "=========================================="echo " WSL2 최적화 상태 점검"echo "=========================================="
echo ""echo "--- 커널 ---"uname -r
echo ""echo "--- 메모리 ---"free -h
echo ""echo "--- 스왑 (zram 포함) ---"swapon --show
echo ""echo "--- zram ---"zramctl 2>/dev/null || echo "zram 없음"
echo ""echo "--- sysctl 핵심값 ---"echo "vm.swappiness = $(cat /proc/sys/vm/swappiness)"echo "vm.vfs_cache_pressure = $(cat /proc/sys/vm/vfs_cache_pressure)"echo "vm.dirty_ratio = $(cat /proc/sys/vm/dirty_ratio)"echo "fs.inotify.max_user_watches = $(cat /proc/sys/fs/inotify/max_user_watches)"
echo ""echo "--- earlyoom ---"systemctl is-active earlyoom 2>/dev/null
echo ""echo "--- 캐시 드롭 타이머 ---"systemctl is-active wsl2-drop-cache.timer 2>/dev/null
echo ""echo "--- .wslconfig ---"cat /mnt/c/Users/*/. wslconfig 2>/dev/null || echo "확인 불가"정리: Before vs After
| 항목 | Before | After |
|---|---|---|
| WSL 메모리 상한 | 16GB (기본 50%) | 12GB |
| 메모리 반환 | gradual (버그) | dropCache (즉시 반환) |
| zram | 없음 | 5.8GB 압축 스왑 |
| swappiness | 60 (기본) | 100 (zram 최적) |
| OOM 방지 | 없음 (터지면 끝) | earlyoom (빌드부터 킬) |
| 캐시 관리 | 수동 | 5분마다 자동 드롭 |
| 불필요 서비스 | 18개 실행 | 14개로 축소 |
| 로그 크기 | 무제한 (688MB 쌓임) | 100MB 제한 |
| Node.js 힙 | 무제한 | 2GB 제한 |
체감 효과
- Windows 작업 관리자에서 vmmem이 20GB → 12GB 이하로 감소
- 팬 소음 체감 50% 감소
- AI 코딩 도구 3개 + 빌드를 동시에 돌려도 뻗지 않음
- 빌드가 메모리를 폭발적으로 먹어도 earlyoom이 안전하게 킬
💬 댓글