WSL2 메모리 최적화 완벽 가이드 - 32GB 시스템에서 뻗지 않는 개발환경 만들기WSL2 메모리 최적화 완벽 가이드 - 32GB 시스템에서 뻗지 않는 개발환경 만들기

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는 한번 잡은 메모리를 자발적으로 잘 안 놓아줍니다.

진단 명령어

Terminal window
# WSL 내부에서 메모리 상태 확인
free -h
# 메모리 많이 먹는 프로세스 확인
ps aux --sort=-%mem | head -20
# 스왑 상태
swapon --show

2단계: Windows 쪽 설정 (.wslconfig)

가장 중요한 설정입니다. 이 파일이 WSL2 VM의 리소스 상한을 결정합니다.

파일 위치

C:\Users\{사용자이름}\.wslconfig

권장 설정 (32GB 시스템 기준)

[wsl2]
memory=12GB
swap=4GB
localhostForwarding=true
nestedVirtualization=false
guiApplications=true
[experimental]
# ⚠️ 가장 중요한 설정!
# 미사용 메모리를 즉시 Windows에 반환
autoMemoryReclaim=dropCache
# 데이터 손상 버그로 Microsoft가 내부적으로 비활성화함
# 절대 true로 설정하지 마세요 (GitHub Issue #12103)
sparseVhd=false

autoMemoryReclaim 옵션 비교

모드동작권장 여부
dropCache캐시 메모리 즉시 반환권장 (2024.05부터 기본값)
gradual5분 idle 후 천천히 반환❌ Docker/systemd 충돌 버그
disabled반환 안 함

⚠️ gradual을 쓰면 안 되는 이유

  • Docker Desktop의 Resource Saver 모드와 충돌하여 WSL이 멈춤 (GitHub #11066)
  • systemd 활성화 상태에서 명령어가 행 (GitHub #10675)

설정 적용

Terminal window
# PowerShell (관리자 권한)
wsl --shutdown
# 이후 WSL 다시 시작

12GB가 합리적인 이유

autoMemoryReclaim=dropCache와 함께 사용하면 memory 값은 **“예약”이 아니라 “천장”**입니다:

  • WSL이 6GB만 쓰면 → 나머지 6GB는 Windows에 즉시 반환
  • WSL이 12GB까지 필요하면 → 12GB까지 사용 가능
  • Windows에는 항상 20GB+ 여유 유지

3단계: zram 활성화 (압축 스왑)

zram은 메모리의 일부를 압축해서 실질적으로 사용 가능한 메모리를 늘려줍니다.

설치 및 활성화

Terminal window
# zram-config 설치
sudo apt update && sudo apt install -y zram-config
# 서비스 시작
sudo systemctl start zram-config
sudo 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에 맞게 최적화합니다.

설정 파일 생성

Terminal window
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=10
vm.dirty_background_ratio=5
# 최소 free 메모리 확보 (128MB)
vm.min_free_kbytes=131072
# 워터마크 조정
vm.watermark_boost_factor=0
vm.watermark_scale_factor=125
# proactive memory compaction
vm.compaction_proactiveness=50
# 대규모 프로젝트 파일 워치 수
fs.inotify.max_user_watches=524288
EOF

즉시 적용

Terminal window
sudo sysctl --system

각 설정값의 의미

파라미터기본값설정값이유
vm.swappiness60100zram이 있으므로 적극적으로 압축 스왑 활용
vm.vfs_cache_pressure10050WSL2의 파일시스템(9P)은 캐시 의존도가 높음. 너무 날리면 느려짐
vm.dirty_ratio2010쓰기 대기 메모리를 줄여서 메모리 압박 감소
vm.min_free_kbytes자동131072128MB를 항상 비워두어 OOM 방지
fs.inotify.max_user_watches8192524288VS 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)"
fi
SCRIPT
sudo chmod +x /usr/local/bin/wsl2-drop-cache

systemd 타이머 설정 (5분마다)

Terminal window
# 서비스 파일
sudo tee /etc/systemd/system/wsl2-drop-cache.service > /dev/null << 'EOF'
[Unit]
Description=WSL2 Drop Cache When Idle
[Service]
Type=oneshot
ExecStart=/usr/local/bin/wsl2-drop-cache
EOF
# 타이머 파일
sudo tee /etc/systemd/system/wsl2-drop-cache.timer > /dev/null << 'EOF'
[Unit]
Description=WSL2 Cache Drop Timer (every 5 min)
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
Persistent=true
[Install]
WantedBy=timers.target
EOF
# 활성화
sudo systemctl daemon-reload
sudo systemctl enable --now wsl2-drop-cache.timer

6단계: earlyoom (OOM 크래시 방지)

이것이 가장 중요한 안전장치입니다. 메모리가 바닥나기 전에 빌드 프로세스를 안전하게 종료합니다.

earlyoom 없이 메모리가 부족하면?

  1. 리눅스 OOM Killer가 아무 프로세스나 죽임
  2. 또는 WSL2 VM 전체가 뻗음
  3. Windows까지 먹통 → 강제 재부팅

earlyoom이 있으면?

  1. 메모리 8% 이하 → 경고 로그
  2. 메모리 5% 이하 → 빌드 프로세스(npm, webpack, tsc)를 먼저 킬
  3. WSL2와 Windows는 안전하게 유지

설치 및 설정

Terminal window
sudo apt install -y earlyoom
Terminal window
# 설정 파일
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 서버용 패키지가 기본 설치되어 있습니다. 개발환경에서 필요 없는 것들이 많습니다.

비활성화할 서비스

Terminal window
# 클라우드 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.service
sudo systemctl mask packagekit.service

제거할 패키지

Terminal window
# snap (설치된 앱이 없다면)
sudo apt purge -y snapd
# 음성인식 라이브러리 (??)
sudo apt purge -y pocketsphinx-en-us libpocketsphinx3
# cloud-init
sudo apt purge -y cloud-init cloud-guest-utils
# landscape
sudo apt purge -y landscape-client landscape-common
# 고아 패키지 정리
sudo apt autoremove -y
# apt 캐시 정리
sudo apt clean

journald 로그 크기 제한

Terminal window
sudo mkdir -p /etc/systemd/journald.conf.d
sudo tee /etc/systemd/journald.conf.d/size-limit.conf > /dev/null << 'EOF'
[Journal]
SystemMaxUse=100M
RuntimeMaxUse=50M
EOF
sudo systemctl restart systemd-journald

8단계: 앱 레벨 메모리 제한

Node.js와 Java는 기본적으로 메모리를 많이 씁니다. 상한을 걸어줍니다.

~/.bashrc에 추가

Terminal window
# Node.js: 프로세스당 최대 힙 2GB
export NODE_OPTIONS="--max-old-space-size=2048"
# Java
export JAVA_OPTS="-Xmx2g -XX:+UseG1GC -XX:+UseContainerSupport"
export MAVEN_OPTS="-Xmx1g"
export GRADLE_OPTS="-Xmx1g"

최종 점검 스크립트

모든 설정이 제대로 적용되었는지 한번에 확인하는 스크립트입니다.

#!/bin/bash
echo "=========================================="
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

항목BeforeAfter
WSL 메모리 상한16GB (기본 50%)12GB
메모리 반환gradual (버그)dropCache (즉시 반환)
zram없음5.8GB 압축 스왑
swappiness60 (기본)100 (zram 최적)
OOM 방지없음 (터지면 끝)earlyoom (빌드부터 킬)
캐시 관리수동5분마다 자동 드롭
불필요 서비스18개 실행14개로 축소
로그 크기무제한 (688MB 쌓임)100MB 제한
Node.js 힙무제한2GB 제한

체감 효과

  • Windows 작업 관리자에서 vmmem이 20GB → 12GB 이하로 감소
  • 팬 소음 체감 50% 감소
  • AI 코딩 도구 3개 + 빌드를 동시에 돌려도 뻗지 않음
  • 빌드가 메모리를 폭발적으로 먹어도 earlyoom이 안전하게 킬

참고 자료

자주 묻는 질문

Windows의 %UserProfile%\.wslconfig 파일에서 memory=12GB로 상한을 설정하고, [experimental] 섹션에 autoMemoryReclaim=dropCache를 추가하세요. 이렇게 하면 WSL2가 사용하지 않는 메모리를 즉시 Windows에 반환합니다.
dropCache를 사용하세요. gradual 모드는 Docker Desktop의 Resource Saver 모드와 충돌하여 WSL이 멈추는 버그가 있고(GitHub Issue #11066), systemd와도 호환 문제가 있습니다(Issue #10675). Microsoft도 2024년 5월부터 dropCache를 기본값으로 변경했습니다.
네, 효과가 있습니다. WSL2는 Hyper-V VM 위에서 동작하지만, zram은 VM 내부에서 메모리를 2~3배 압축하여 실질적으로 사용 가능한 메모리를 늘려줍니다. 12GB 시스템에서 약 5.8GB의 압축 스왑이 추가됩니다.
earlyoom을 설치하세요. 메모리가 5% 이하로 떨어지면 OOM killer가 작동하기 전에 빌드 프로세스(npm, webpack, tsc 등)를 먼저 안전하게 종료합니다. sudo apt install earlyoom으로 설치 가능합니다.
12~16GB를 권장합니다. autoMemoryReclaim=dropCache 설정과 함께 사용하면 memory 값은 '예약'이 아니라 '천장'으로 작동합니다. WSL이 6GB만 쓰면 나머지 6GB는 Windows에 즉시 반환됩니다.

💬 댓글