9부에서 GitLab을 데스크탑에 세우고 작업하는 동안 하루에 몇 번씩 가까이 뭔가가 죽었다.
GitLab이 내려가고, Chrome 탭이 비워지고, VS Code가 다시 뜨고, Docker Desktop이 아예 시작을 못 했다.
작업 관리자를 열면 메모리가 80퍼센트를 넘어 있었다. 물리 램이 모자란다고 판단하고
DDR3 4GB 네 장 중 두 장을 8GB로 바꿀 주문을 넣었다.그런데 원인은 램이 아니었다. 이 글은 그 판단이 왜 틀렸는지, 무엇이 진짜 원인이었는지,
어떻게 찾아서 고쳤는지를 순서대로 적은 것이다.원인을 가리려면 무엇이 무엇 위에 있는지부터 알아야 했다. WSL2·배포판·컨테이너·
Vmmem이
각각 무엇이고 어느 층에 있는지를 갈라 놓고 시작한다.
0. 무엇이 안 잡혔나
말로 못 하던 것들이 이랬다.
Docker Desktop · docker · dockerd · WSL2 · wsl · 배포판 · 컨테이너 · Vmmem
이름은 다 들어 봤는데 무엇이 무엇 위에 있는지가 안 그려졌다. 그 상태로는 작업 관리자에서 Vmmem이 1위인 것을 봐도 그게 무엇인지조차 몰랐고, 화면에 OOMKilled가 찍혀도 어느 층에서 난 일인지 가릴 수 없었다.
그래서 층부터 갈랐다. 무엇이 무엇 위에 서 있는지를 모르면 어디를 손댈지도 모른다.
1. 개념 — 무엇이 무엇 위에 있나
출발점은 이것 하나다. 이 데스크탑의 Windows에 WSL2를 켜고 Ubuntu 배포판을 깔아서 써 왔다. Vmmem이 무엇이고 왜 그렇게 먹는지를 알려면 그 두 단어부터 갈라야 한다.
1.1 WSL2 — Windows 안에 띄운 가상머신
WSL2는 Windows 안에서 리눅스 커널을 실제로 부팅시키는 가상머신이다. "실제로"가 핵심이고, 그게 이전 세대와 갈리는 지점이다.
WSL1 가상머신이 아니었다. 리눅스 커널이 없었다.
리눅스 프로그램이 커널에 하는 요청을 Windows 커널이 받아 바꿔 처리했다
→ 커널 기능 자체가 필요한 도커는 아예 못 돌았다
WSL2 가상머신이다. 리눅스 커널이 그 안에서 부팅한다
→ cgroup · namespace 가 진짜로 있다 → 도커가 돈다
커널이 실제로 있는지는 명령 한 줄로 확인된다.
wsl --version
WSL 버전: 2.7.11.0
커널 버전: 6.18.33.2
리눅스 커널이 버전까지 찍힌다. Microsoft가 만들어 배포하는 커널이고, 이것이 안에서 부팅해 있다는 뜻이다.
그 가상머신은 무엇 위에 올라가나 — 하이퍼바이저
컴퓨터 한 대에 OS는 원래 하나다. CPU도 메모리도 디스크도 그 OS가 전부 자기 것으로 쓴다. OS를 둘 이상 동시에 돌리려면 그것들을 나눠서, 서로의 존재를 모른 채 쓰게 해 줄 층이 하나 필요하다. 그 층이 하이퍼바이저다.
하는 일 CPU 시간 · 메모리 영역 · 디스크를 게스트마다 잘라서 준다
한 게스트가 다른 게스트의 메모리를 못 건드리게 막는다
Type 1 하드웨어 바로 위에서 돈다 Hyper-V · KVM(Proxmox) · ESXi
Type 2 OS 위에서 앱으로 돈다 VirtualBox · VMware Workstation
WSL2를 켤 때 Windows 기능에서 Virtual Machine Platform을 켜는데, 그것이 Windows의 하이퍼바이저 Hyper-V다. Proxmox VE 쪽은 Debian 리눅스 커널에 모듈로 들어 있는 KVM이 같은 자리에 있다. 둘 다 Type 1이고, OS에 이미 딸려 온 것을 켜서 쓴다. VirtualBox처럼 따로 설치하는 프로그램이 아니다.
여기서 순서가 한 번 뒤집힌다. 하이퍼바이저를 켜면 그것을 켠 OS 자신도 하이퍼바이저 아래로 내려앉는다.
물리 하드웨어
└ Hyper-V (하이퍼바이저)
├ Windows 자신 ← 게스트가 된다
└ WSL2 VM → 리눅스 커널 6.18.33.2
켜기 전에는 Windows가 하드웨어를 직접 쓰지만, 켜고 나면 하이퍼바이저가 하드웨어를 잡는다. WSL2 VM은 Windows 밑이 아니라 Windows 옆에 나란히 놓인다. Proxmox도 같아서, Debian이 KVM을 켜는 순간 그 Debian도 VM 3대와 나란한 자리로 내려간다.
Proxmox만 특별한 방식이 아니다. 노트북에서 하던 것과 데스크탑에서 도는 것이 같은 구조이고, 다른 것은 그 위에 무엇을 올렸느냐뿐이다.
구조는 같고 방향이 반대다
Proxmox 서버 한 대를 여러 대로 나눠 쓴다 게스트를 호스트에서 떼어낸다
WSL2 Windows 에서 리눅스를 쓴다 게스트를 호스트에 붙인다
그 방향 차이가 네 군데에서 나온다.
① 메모리를 받는 방식
Proxmox VM 만들 때 8GB 로 지정하면 켜져 있는 동안 계속 8GB 를 점유한다
WSL2 VM Windows 의 물리 메모리에서 그때그때 받아 온다
0 에서 시작해 상한까지 오르내린다
WSL2는 받아 오는 곳이 Windows의 물리 메모리다. 별도로 떼어 둔 몫이 없으니, VM이 커지는 만큼 Windows 쪽에서 그만큼이 빠진다.
물리 16GB
├ Windows 앱들이 쓰는 몫
└ WSL2 VM 이 받아 간 몫 0 에서 상한 사이를 오르내린다
상한이 있고, 그 상한은 Windows 쪽 설정 파일이 정한다. 어느 파일에 무엇을 적어 뒀는지는 배포판을 다룬 뒤에 연다.
켜 놓은 채로도 쓰는 양이 계속 오르내린다. 안에서 뭔가 돌면 더 받아 오고, 한가해지면 일부를 돌려준다. Windows 쪽에서 그 오르내림이 어떤 숫자로 보이는지는 뒤의 Vmmem 절에서 다룬다.
② 켜져 있는 시간
Proxmox VM 켜 두면 계속 떠 있다
WSL2 VM 아무것도 안 켜면 VM 자체가 없다. 명령 하나를 치는 순간 뜬다
③ 부팅
Proxmox VM BIOS/UEFI → 부트로더 → 커널 → init 수십 초
WSL2 VM 커널 이미지를 바로 올린다. 부트로더가 없다 1초 안쪽
④ 호스트와의 경계
Proxmox VM 완전히 분리. 네트워크로만 닿는다 (SSH)
WSL2 VM /mnt/c 로 Windows 디스크가 들어와 있다
localhost 를 Windows 와 공유한다
리눅스 셸에서 .exe 를 실행할 수 있다
그중 작업 방식을 정하는 것이 /mnt/c다. 같은 파일을 두 이름으로 보는 것이라 복사본이 아니다(마운트의 효과 — Windows 드라이브를 리눅스 파일시스템 안의 한 자리에 붙여 둔 것).
Windows C:\Users\on\Desktop\loadmap\cgv-infra\...
Linux /mnt/c/Users/on/Desktop/loadmap/cgv-infra/...
VS Code에서 저장하면 리눅스 셸에서 바로 읽힌다. Proxmox VM이었으면 scp로 옮겨야 했을 일이다.
넷 중 이 글에 걸리는 것
넷째, 호스트와의 경계가 없는 것이 데스크탑에서 WSL2를 고른 이유다. VS Code로 Windows 쪽에서 편집하고 같은 파일을 리눅스에서 빌드한다. 옮기는 절차가 없다.
그것을 얻은 대가가 첫째와 둘째다.
메모리를 빌려 온다 떼어 받은 메모리라면 Windows 가 모자라도 VM 은 자기 몫을 쥔다
빌려 오니 Windows 쪽이 막히면 VM 도 같이 막힌다
필요할 때만 뜬다 없다가 생기고, 생기면 커지고, 커지면 잘 안 줄어든다
숫자가 계속 움직여서 무엇이 정상인지 잡히지 않는다
k3s 노드는 서로 떨어져 있어야 하니 Proxmox가 맞고, 데스크탑에서 파일을 옮기지 않고 두 쪽을 오가려면 WSL2가 맞다. 호스트에 붙인 대가로 호스트 사정도 같이 넘어온다.
다루는 명령은 wsl 하나다
wsl -l -v 뭐가 켜져 있나
wsl -d <이름> 그것으로 들어간다
wsl --terminate 하나를 내린다
wsl --shutdown VM 을 통째로 내린다
<이름> 자리에 무엇이 들어가는지가 다음 절이다. 커널은 섰지만, 커널만으로는 명령 한 줄 못 친다.
1.2 커널과 배포판
둘이 각각 무엇을 하는지는 ls 한 줄을 따라가면 갈린다.
ls 하나를 칠 때 무슨 일이 나나
$ ls
① bash 가 "ls" 라는 파일을 찾는다 /usr/bin/ls
② bash 가 커널에게 부탁한다 "이 파일 실행해 줘"
★ ③ 커널이 디스크를 읽어 메모리에 올린다 → ls 프로세스가 뜬다
④ ls 가 커널에게 부탁한다 "이 디렉터리에 뭐 있는지 알려 줘"
★ ⑤ 커널이 디스크를 실제로 읽어서 알려 준다
⑥ ls 가 화면에 찍는다
★ = 디스크를 실제로 건드리는 단계. 둘 다 커널이 한다
커널 — 하드웨어를 직접 만지는 유일한 것
커널이 독점하는 것 CPU 시간 배분 · 메모리 할당 · 디스크 읽고 쓰기 · 네트워크 카드
프로그램이 하는 것 커널에게 부탁한다 (= 시스템콜)
왜 독점하나. 프로그램이 하드웨어를 직접 만지면 서로 같은 메모리를 덮어쓰고 같은 디스크를 동시에 긁는다. 그래서 창구를 하나로 몰았고, 그 창구가 커널이다.
배포판 — 커널에게 부탁하는 프로그램들의 묶음
위 ①의 bash, ②의 ls, 그리고 /usr/bin이라는 디렉터리 자체까지 전부 배포판이 넣어 준 것이다.
셸 명령을 입력받을 창구 (bash)
기본 명령어 ls · cp · ps · grep
패키지 관리자 프로그램을 설치하는 도구 (apt · dnf · apk)
디렉터리 배치 /etc · /usr · /var 를 어디에 어떻게 둘지
초기화 시스템 부팅하며 뭘 순서대로 띄울지 (systemd)
"리눅스"는 원래 "커널 이름"이고, 위를 골라 한 벌로 묶어 놓은 것이 배포판이다. 누가 어떻게 묶었느냐로 이름이 갈린다.
Ubuntu · Debian 패키지 apt · .deb
Rocky · RHEL · CentOS 패키지 dnf · .rpm
Alpine 패키지 apk. 작아서 컨테이너 베이스로 많이 쓴다
커널만 있으면 부팅이 끝까지 못 간다
리눅스가 켜지는 순서는 이렇다.
① 커널을 메모리에 올린다
② 커널이 하드웨어를 초기화한다 CPU · 메모리 · 디스크 · NIC 인식
③ 커널이 루트 파일시스템(/)을 마운트한다
④ 커널이 /sbin/init 을 실행한다 PID 1
⑤ init 이 나머지를 띄운다 로그 · 네트워크 · sshd · 셸
커널이 직접 하는 것은 ①②까지다. ③의 /도 ④의 /sbin/init도 커널 안에 없다 — 배포판이 준다. 없으면 이 줄에서 멈춘다.
Kernel panic - not syncing: No init found.
명령이 안 먹는 정도가 아니라 프롬프트를 띄울 bash 자체가 없다.
내가 미리 예전에 깐 것이 Ubuntu 배포판이다
실물은 Windows에 있는 파일 하나다.
Get-ChildItem "$env:LOCALAPPDATA\wsl" -Recurse -Filter "ext4.vhdx" | Select-Object FullName
C:\Users\on\AppData\Local\wsl\{a3e25de2-...}\ext4.vhdx
vhdx는 가상 디스크 파일이고, 그 안에 리눅스 파일시스템 하나가 통째로 들어 있다. 부팅 ③에서 커널이 /로 마운트하는 것이 이 파일이다.
열어 보면 디렉터리 구조가 그대로 나온다.
wsl -d Ubuntu -- ls /
bin boot dev etc home lib media mnt opt proc root
run sbin snap srv sys tmp usr var
정체와 커널을 각각 물어보면 답이 갈린다.
wsl -d Ubuntu -- cat /etc/os-release
wsl -d Ubuntu -- uname -r
PRETTY_NAME="Ubuntu 24.04.4 LTS"
6.18.33.2-microsoft-standard-WSL2
배포판은 Ubuntu인데 커널은 Microsoft가 만든 것이다. 둘이 따로라는 것이 이 두 줄에서 확인된다.
부팅 ④의 /sbin/init도 그 파일 안에 있다.
wsl -d Ubuntu -- ps aux
USER PID COMMAND
root 1 /sbin/init ← Ubuntu 의 ext4.vhdx 에 든 파일이 PID 1 이 됐다
root 43 systemd-journald
root 151 systemd-resolved
여기까지로 완성된 것
WSL2 VM ─ 리눅스 커널 6.18.33.2 Microsoft 가 준다. 고를 여지가 없다
└ Ubuntu 배포판 내가 깔았다. ext4.vhdx 파일 하나
bash · ls · apt · systemd · /etc · /home
부팅 ①에서 ⑤까지가 다 돌았다는 증거가 "wsl"명령어로 들어가는 프롬프트다.
PS C:\Users\on\Desktop\loadmap> wsl
on@DESKTOP-BSPGJMO:/mnt/c/Users/on/Desktop/loadmap$
이 프롬프트가 Ubuntu 배포판이 준 bash다. 커널만 있었으면 이 줄이 안 나온다. 여기서 kubectl·kubeseal·git을 치면 먹는다.
Windows 안에 리눅스가 섰다. 여기에 필요한 것을 apt로 얹으면 되는 상태다.
그 VM에 준 자원 — .wslconfig
VM이 Windows에서 받아 갈 수 있는 상한은 Windows 쪽 파일 하나로 정한다. 리눅스 안이 아니라 밖이다.
C:\Users\on\.wslconfig
[wsl2]
memory=6GB
processors=6
swap=4GB
memory VM 이 Windows 물리 메모리에서 받아 갈 수 있는 최대치
processors VM 에 줄 논리 프로세서 수 (i7-2600K 8스레드 중 6)
swap VM 안의 스왑. Windows 페이지파일과는 별개
파일이 없으면 기본값이 쓰인다. memory 기본값은 물리의 절반이라 이 데스크탑에서는 8GB가 된다. 6GB로 낮춘 것은 Windows 쪽에 자리를 남기려던 것이다.
바꾼 값은 VM을 다시 띄워야 먹는다.
wsl --shutdown
.wslconfig가 정하는 것은 상한 하나뿐이다. 실제로 얼마를 받아 가는지는 그때그때 달라진다.
1.3 GitLab을 어떻게 세울 것인가
여기까지가 데스크탑 환경이었다 — WSL2 가상머신 하나에 Ubuntu 배포판 하나. 그 상태에서 프로젝트를 이어가려면 GitLab을 이 데스크탑에 세워야 했다.
GitLab이 요구하는 환경
OS 리눅스만. Windows 에서는 어떤 방식으로도 네이티브로 안 돈다
CPU 4코어 권장 (최소 2)
RAM 4GB 필수 최소, 8GB 권장. swap 은 별도로 더 필요
디스크 설치에 2.5GB + 저장소 데이터
이 데스크탑과 대조하면 걸리는 줄이 하나다.
요구 이 데스크탑
──────────────────────────────────────────────
리눅스 WSL2 안에 커널이 있다 ✅
4코어 .wslconfig processors=6 ✅
디스크 C 드라이브 여유 49.7GB ✅
RAM 4GB VM 상한이 6GB. Ubuntu 배포판과 나눠 쓴다 ← 여기
GitLab 최소가 4GB인데 VM 전체가 6GB다. 그 6GB를 Ubuntu 쪽 작업(kubectl·빌드)과 나눠 쓰면 남는 것이 2GB 남짓이다. 그래서 GitLab 쪽 설정을 눌러 공식 최소 아래로 돌리고 있고, 무엇을 눌렀는지는 방식을 고른 뒤 기동 파일에서 같이 본다.
세울 수 있는 방법 셋
① Ubuntu 배포판에 직접 설치 apt install gitlab-ce. 도커 없이
② Docker Desktop 을 깔고 컨테이너로
③ Ubuntu 배포판에 도커 엔진만 깔고 컨테이너로
k3s 클러스터에 Helm으로 올리는 길과 노트북에 VM을 하나 더 두는 길도 있지만, 노드 RAM 8GB에 LGTM 스택이 이미 돌고 노트북 RAM도 노드 3대에 배분돼 있어 자리가 없다.
① Ubuntu 배포판에 직접 설치
sudo apt install gitlab-ce
WSL2 VM
└ 리눅스 커널
└ Ubuntu 배포판
└ gitlab-ce 패키지 PostgreSQL · Redis · nginx 가 같이 깔린다
얻는 것 셋 중 제일 가볍다. GitLab 말고 얹히는 것이 없다
치르는 것 GitLab 이 그 Ubuntu 를 점유한다. 앞으로 무엇을 깔든 한 공간을 쓴다
apt purge 해도 설정과 데이터가 남는다
버전을 올렸다 문제가 생기면 배포판째 되돌려야 한다
→ 미리 wsl --export 로 통째 백업을 해 뒀어야 한다
GitLab은 서비스로 돌아야 해서 systemd가 필요하다. WSL2는 지원하지만 기본이 꺼져 있어 켜야 한다.
# /etc/wsl.conf
[boot]
systemd=true
② Docker Desktop을 깔고 컨테이너로
Windows
├ Docker Desktop.exe 앱. GUI · 자동 업데이트 · 백엔드 관리
└ WSL2 VM
├ Ubuntu 배포판
└ docker-desktop 배포판 앱이 자기 몫으로 깐 것
└ dockerd
└ gitlab 컨테이너
Docker Desktop은 Windows 앱이고, 깔면 배포판과 엔진이 따라온다. GitLab은 그 엔진이 만든 컨테이너 안에서 돈다.
얻는 것 GUI 로 컨테이너 · 이미지 · 볼륨을 본다
엔진 설치와 업데이트를 앱이 한다
WSL 통합 설정을 앱이 해 준다
치르는 것 배포판이 하나 더 생긴다 (docker-desktop)
Windows 쪽에 앱 프로세스가 뜬다 — 작업 관리자에서 약 200MB
로그인하면 자동으로 뜬다 (설정으로 끌 수 있다)
③ Ubuntu 배포판에 도커 엔진만 깔기
sudo apt install docker-ce
docker compose up -d
WSL2 VM
└ 리눅스 커널
└ Ubuntu 배포판
└ dockerd (엔진)
└ gitlab 컨테이너 그 안에 리눅스 한 벌 + GitLab
컨테이너로 돌리는 것은 ②와 똑같다. 다른 것은 엔진을 앱이 관리하느냐 내가 apt로 깔고 관리하느냐뿐이고, 그 차이로 배포판 하나와 Windows 앱이 빠진다.
얻는 것 배포판은 그대로 1개인데 GitLab 이 Ubuntu 를 점유하지 않는다
PostgreSQL · Redis · nginx 가 전부 컨테이너 안에서 끝난다
이미지 태그가 버전을 고정한다. 문제가 생기면 태그만 바꿔 다시 띄운다
지울 때 컨테이너와 볼륨만 지우면 Ubuntu 는 그대로다
치르는 것 dockerd 가 뜬다. ① 보다 그만큼 더 쓴다
엔진 설치 · 업데이트 · WSL 설정을 직접 한다
GUI 가 없다. 상태는 docker ps · docker stats 로 본다
셋을 나란히
① 직접 설치 ② Docker Desktop ③ 엔진 직접
────────────────────────────────────────────────────────────────────────────
배포판 1개 2개 1개
추가로 뜨는 것 없음 dockerd + Windows 앱 dockerd
GitLab 이 사는 곳 Ubuntu 안 컨테이너 안 컨테이너 안
버전 되돌리기 배포판째 백업/복원 태그를 바꾼다 태그를 바꾼다
지운 뒤 잔재가 남는다 Ubuntu 그대로 Ubuntu 그대로
관리 손수 앱이 해 준다 손수
② "Docker Desktop을 깔고 컨테이너로" 방식을 골랐다
메모리만 놓고 보면 셋의 차이는 수백 MB다. GitLab 본체가 2.87GB이므로 어느 쪽을 골라도 그것이 제일 큰 몫이고, 뒤에 겪은 크래시도 이 선택과는 무관했다.
갈리는 것은 다루기 쉬움이다. ①은 버전을 되돌리려면 배포판을 통째로 백업해 뒀어야 하고, ②③은 이미지 태그만 바꾸면 된다. 처음 세워 보는 것이라 설정을 바꿔 가며 다시 띄울 일이 많았으므로 ②③ 쪽이 맞았다.
②와 ③ 사이에서는 ③이 같은 이득을 더 가볍게 준다. 배포판 하나와 Windows 앱 200MB를 안 쓰고 끝난다. 그것을 모르고 ②를 골랐다.
기동 파일 — 4GB 최소를 어떻게 눌렀나
컨테이너를 어떤 설정으로 띄울지는 docker-compose.yml 한 장에 적는다.
services:
gitlab:
image: gitlab/gitlab-ce:19.2.1-ce.0
container_name: gitlab
restart: unless-stopped
shm_size: '256m'
ports: ['8929:8929', '2424:22']
environment:
GITLAB_OMNIBUS_CONFIG: |
external_url 'http://192.168.0.167:8929'
puma['worker_processes'] = 0
sidekiq['max_concurrency'] = 10
prometheus_monitoring['enable'] = false
gitlab_kas['enable'] = false
아래 넷이 공식 최소 4GB를 2GB대로 끌어내린 설정이다.
puma worker_processes = 0 웹 요청을 받는 워커 프로세스를 안 띄운다
마스터 하나가 직접 처리한다. 혼자 쓰니 동시 요청이 없다
sidekiq max_concurrency = 10 백그라운드 작업 스레드 수. 기본 20 의 절반
prometheus_monitoring = false GitLab 이 자체 내장한 감시 스택을 끈다
exporter 프로세스가 여럿 안 뜬다
gitlab_kas = false 쿠버네티스 에이전트 서버. 안 쓰는 기능이라 끈다
넷 다 "프로세스 수를 줄이는" 설정이다. GitLab이 무거운 이유가 기능 하나가 커서가 아니라 한 컨테이너 안에서 여럿이 같이 뜨기 때문이라, 안 쓰는 것을 빼는 것이 제일 크게 듣는다.
restart: unless-stopped도 뒤에 걸린다. 엔진이 뜨면 GitLab이 따라 뜬다는 뜻이라, 내가 켜지 않아도 로그인만 하면 올라와 있다.
1.4 그렇게 세우니 무엇이 생겼나
docker compose up을 친 것이 전부였다. 실제로 무엇이 생겼는지는 명령 두 줄로 확인된다.
배포판이 하나 더 생겼다
wsl -l -v
* Ubuntu Running
docker-desktop Stopped
docker-desktop은 내가 깐 적이 없는데 목록에 있다. Docker Desktop이 엔진을 둘 자리로 만든 것이다.
State 칸의 뜻은 이렇다.
Running 그 배포판의 ext4.vhdx 안에 든 프로그램들이 프로세스로 돌고 있다
Stopped 파일은 그대로 있고, 돌고 있는 것이 하나도 없다
Stopped는 없어진 것이 아니다. 파일은 그대로 있고 아무것도 안 돌 뿐이라, 명령 한 줄이면 다시 Running이 된다.
내 Ubuntu에 얹지 않고 따로 깐 이유는 앱이 업데이트할 때 그 배포판을 통째로 갈아엎기 때문이다. 내 Ubuntu에 얹었으면 Docker를 갱신할 때마다 거기 깔아 둔 것이 날아간다.
이름이 겹쳐서 헷갈리는 것 셋을 갈라 두면 이렇다.
Docker Desktop Windows 앱. 아이콘으로 켜는 것
docker-desktop 배포판. wsl -l -v 에 나오는 것. 엔진(dockerd)이 여기 산다
docker 명령어. Windows 에 있다. 엔진에 지시만 보낸다
GitLab은 그 위에(docker-desktop 위에) 얹었다.
docker-compose.yml C:\Users\on\Desktop\loadmap\gitlab\
docker compose up -d PowerShell 에서 친다
→ docker (Windows) 가 dockerd (VM 안) 에 지시를 보낸다
→ dockerd 가 gitlab/gitlab-ce 이미지로 컨테이너를 띄운다
→ 그 안에서 프로세스 아홉이 돈다
docker 명령이 Windows에 있어서 PowerShell에서 친다. Ubuntu 배포판 쪽에서는 안 먹는다 — Docker Desktop의 WSL 통합을 그 배포판에 대해 안 켰기 때문이다.
그런데 가상머신은 여전히 하나다
가상머신 1개 Get-Process vmmem 을 쳐도 vmmem 하나만 나온다
커널 1개 두 배포판 다 6.18.33.2-microsoft-standard-WSL2
배포판 2개 Ubuntu · docker-desktop
컨테이너 1개 gitlab
배포판이 늘어도 VM은 안 는다. GitLab 컨테이너도 마찬가지다 — 자기 커널이 없어서 VM의 커널을 빌려 쓴다.
그래서 결과가 하나 나온다.
.wslconfig 의 memory=6GB 는 배포판마다 6GB 가 아니라, 둘이 합쳐 6GB 다
Ubuntu 쪽 작업과 GitLab이 각자 몫을 갖는 것이 아니라 한 통을 나눠 쓴다. 한쪽이 커지면 다른 쪽이 밀린다.
1.5 Vmmem — VM 전체를 Windows가 보는 이름
작업 관리자 목록에 gitlab이라는 줄은 없다. VM 안에 있던 것 전부가 Vmmem 한 줄에 뭉쳐 있다.

Windows가 프로그램을 실행하면 그 메모리는 그 프로세스 앞으로 달린다. 그런데 WSL2 VM은 Windows가 실행하는 프로그램이 아니라 하이퍼바이저가 돌리는 것이라, 어떤 Windows 프로세스에도 안 속한다. 그대로 두면 작업 관리자에서 "메모리가 80퍼센트인데 목록을 다 더해도 그만큼이 안 나오는" 상태가 된다. 그 구멍을 표시하려고 Windows가 만든 자리가 Vmmem이다.
① 프로세스가 아니다 작업 끝내기로 못 끈다. 내리려면 wsl --shutdown
② 안이 안 보인다 배포판 둘과 GitLab 컨테이너가 한 숫자에 뭉쳐 있다
③ CPU 도 대표한다 Vmmem 의 CPU % 는 VM 안 리눅스가 쓰는 양이다
④ 물리 RAM 기준이다 VM 이 요구한 양이 아니라 지금 물리 RAM 에 올라와 있는 양이다
②는 켜 보면 눈으로 확인된다.
PowerShell 에서 wsl 을 쳐서 Ubuntu 배포판을 켠다 → Vmmem 이 오른다
Docker Desktop 에서 GitLab 컨테이너를 켠다 → 같은 Vmmem 이 또 오른다
배포판을 켜든 컨테이너를 켜든 늘어나는 것은 Vmmem 한 줄이다. 목록에 새 줄이 생기지 않는다.
1.6 전체 그림
Windows 10 (물리 16GB, i7-2600K 4코어 8스레드)
│
├─ Docker Desktop.exe 앱. VM 과 엔진을 켜고 끈다
├─ docker.exe 명령어. 엔진에 지시를 보낸다
├─ wsl.exe 명령어. 배포판을 켜고 셸을 연다
│
├─ Chrome · VS Code · Claude Code · Defender
│
└─ WSL2 가상머신 ← 작업 관리자에 Vmmem 으로 보인다
│ 리눅스 커널 6.18.33.2-microsoft-standard-WSL2
│
├─ Ubuntu 배포판 kubectl · kubeseal · kubeconfig
│
└─ docker-desktop 배포판
└─ dockerd
└─ gitlab 컨테이너
nginx · workhorse · puma · sidekiq · postgresql
redis · gitaly · sshd · logrotate 프로세스 아홉
"GitLab은 프로세스인가 컨테이너인가"의 답이 여기 있다 — 둘 다다. 컨테이너 하나 안에 프로세스가 아홉이다.
1.7 켤 때마다 무엇이 오르나
wsl 을 친다 Docker Desktop 아이콘을 클릭한다
──────────────────────────────────────────────────────────────
① VM 을 띄운다 ① VM 을 띄운다 ← 같은 VM 하나
② Ubuntu 배포판을 띄운다 ② docker-desktop 배포판을 띄운다
③ 셸을 하나 연다 ③ 그 안에서 dockerd 를 띄운다
④ dockerd 가 gitlab 컨테이너를 띄운다
⑤ 컨테이너 안에서 프로세스 아홉이 뜬다
둘 다 같은 가상머신을 쓰고, 각자 자기 배포판을 켠다. 그래서 Vmmem이 두 개로 갈라지지 않고 한 숫자가 커진다.
무엇으로 재나 — 명령 넷
wsl -l -v 배포판이 켜져 있나
wsl -d docker-desktop -- free -h VM 전체 장부
docker stats --no-stream 컨테이너별
Get-Process vmmem Windows 가 본 VM 의 몫
free -h에 -d docker-desktop을 쓴 이유가 하나 있다. 이 값은 커널이 보고하는 것이고 커널은 VM에 하나뿐이라, Ubuntu에서 묻든 docker-desktop에서 묻든 같은 숫자가 나온다. 배포판을 고르는 것이 아니라 아무 배포판이나 하나를 통해 커널에게 묻는 것이다.
그런데 -d Ubuntu로 물으면 꺼져 있던 Ubuntu가 그 명령 때문에 켜진다. 재려고 친 명령이 재는 대상을 바꿔 버리므로, 이미 떠 있는 쪽(데스크탑과 함께 자동 부팅되는 docker-desktop)을 통해 묻는다.
free -h는 두 줄을 준다. Mem과 Swap이고, 칸 이름은 두 줄이 같이 쓴다. 각 줄이 무엇인지는 아래에서 하나씩 본다.
total used free shared buff/cache available
Mem: 5.8G 2.9G 483M 97.8M 2.4G 2.6G
Swap: 4.0G 0 4.0G
Mem 줄 — VM 의 물리 메모리
total5.8G — 상한이 정한다.wslconfig의memory=6GB가 출발점이다- VM이 부팅하면서 리눅스 커널이 자기 코드와 자료구조 몫을 먼저 떼어 간다
- 남은 것이
total이라 6GB를 줬는데 5.8G로 보인다 - VM 안에서 무슨 짓을 해도 이 위로는 못 간다.
memory를 8GB로 올리면total도 같이 커진다
used2.9G — 프로세스가 쥐고 있는 양docker stats가 보여준gitlab 2.906GiB와 거의 같다- 컨테이너도 같은 커널 위의 프로세스라 여기 합산된다
- 프로세스가 끝나면 즉시 돌아온다
free483M — 아무도 안 쓰는 순수 빈 공간- 작아 보이지만 이게 정상이다
- 리눅스는 빈 메모리를 놀리지 않는다. 놀려도 얻는 게 없으니 읽은 파일로 채워 둔다
- 그래서 오래 쓸수록
free는 0에 가까워진다. 부족을 뜻하지 않는다
shared97.8M — 프로세스끼리 공유하는 몫tmpfs나/dev/shm같은 공유 메모리다- GitLab 기동 파일의
shm_size: '256m'가 여기 반영된다 used에 이미 포함된 값이라 따로 더하면 안 된다
buff/cache2.4G — 쓰고 있지만 언제든 내놓는 것- 커널이 디스크에서 읽은 내용을 들고 있는 것이다
- 같은 파일을 또 읽으면 디스크에 안 가고 여기서 준다
- 요구가 오면 버려서 내준다.
used와 성격이 다르다used— 프로세스가 요구한 것. 못 뺏는다buff/cache— 커널이 알아서 채운 것. 요구가 오면 내놓는다
- 전부 내놓지는 못한다. 그 예외는
available항목에서 다룬다
available2.6G — 이 칸을 본다- 지금부터 새 프로그램이 받을 수 있는 양이고, 커널이 계산해서 알려 준다
available=free+buff/cache중 버릴 수 있는 부분- 단순히 더한 값보다 작다
free 483M + buff/cache 2.4G = 2.88G available = 2.6G 차이 약 280M ← 못 버리는 몫 buff/cache중 못 버리는 것shared97.8M —tmpfs·/dev/shm. 디스크에 원본이 없어서 버리면 내용이 사라진다- dirty 페이지 — 고쳤는데 아직 디스크에 안 쓴 것. 먼저 써야 버릴 수 있다
- 나머지는 디스크에서 읽어 온 사본이라 버려도 원본이 남는다. 그래서 대부분 회수된다
free가 483M이라고 겁먹을 게 아니라available2.6G가 실제 여유다- 반대로 이 칸이 0에 가까워지면 캐시를 다 버려도 모자란 상태다
세 칸이 total을 나눠 갖는다.
total = used + free + buff/cache
5.8G = 2.9G + 483M + 2.4G
Swap 줄 — 모자랄 때 디스크로 밀어내는 자리
스왑이 무엇인지부터 짚는다.
RAM 이 모자라면
지금 당장 안 쓰는 내용을 디스크에 내보내고 그 자리를 비운다
나중에 그 내용이 필요해지면 디스크에서 다시 읽어 온다
RAM 보다 훨씬 느리지만, 메모리가 모자라 죽는 것은 막는다
"메모리를 늘리는 것"이 아니라 "느려지더라도 버티게 하는 것"이다.
total4.0G —.wslconfig의swap=4GB가 만든 것- VM 안의 스왑이고,
Mem의 5.8G와는 별개로 더 있는 자리다 - 상한
memory=6GB에 포함되는 값이 아니다 - Windows에도 같은 역할을 하는 것이 있고, 그것의 이름이 페이지파일이다
Swap— VM 안. 게스트 리눅스가 자기 몫 5.8G가 모자랄 때 쓴다- 페이지파일 — VM 밖. Windows가 물리 RAM 16GB가 모자랄 때 쓴다
- 층이 달라서 서로 무관하게 동작한다. 하나가 가득 차도 다른 하나는 모른다
- VM 안의 스왑이고,
used0 — 아직 안 쓰고 있다Mem의available이 0에 가까워져야 여기로 밀어내기 시작한다- 밀어내기 시작하면 그만큼 더 버틴다. 그 대신 디스크를 오가느라 느려진다
- 이 값이 오르고 있다면 VM 메모리가 빠듯하다는 신호다
free4.0G — 남은 스왑
출발점 — GitLab만 떠 있는 상태
내가 켠 것이 없어도 로그인만 하면 여기까지 온다.
Docker Desktop 설정 AutoStart=true 로그인하면 앱이 뜬다 (창은 안 열린다)
docker-compose.yml restart: unless-stopped 엔진이 뜨면 GitLab 이 따라 뜬다
Ubuntu는 안 켰다. 그 상태에서 재면 이렇다.
wsl -l -v Ubuntu Stopped / docker-desktop Running
docker stats gitlab 2.906 GiB / 5.787 GiB
free -h total 5.8G used 2.9G free 483M cache 2.4G available 2.6G
Vmmem 2,508 MB
Windows 물리 여유 5.5GB
used 2.9G와 gitlab 2.906GiB가 거의 같다. VM 안에서 쓰는 것의 거의 전부가 GitLab이고, 엔진과 그 배포판은 수십 MB다.
여기서 Ubuntu를 켜면
wsl
3초 간격으로 3분간 재면 이렇게 움직인다.
07:56:41 Vmmem 3,138 MB
07:56:52 Vmmem 3,740 MB
07:57:00 Vmmem 3,781 MB ← 20초 만에 여기까지
07:59:59 Vmmem 3,819 MB ← 그 뒤 3분간 38MB
부팅은 20초 안에 끝나고 그 뒤로는 거의 안 는다.
전후를 나란히
Ubuntu Stopped Ubuntu Running 차이
────────────────────────────────────────────────────────────────
Vmmem 2,508 MB 3,822 MB +1,314 MB
게스트 used 2.9 G 2.9 G 변화 없음
게스트 buff/cache 2.4 G 2.8 G +0.4 G
게스트 available 2.6 G 2.6 G 변화 없음
Windows 물리 여유 5.5 GB 4.1 GB -1.4 GB
게스트 쪽 세 줄 — VM 안에서 무슨 일이 있었나
used 2.9 G → 2.9 G Ubuntu 프로세스 약 120MB 는 반올림에 묻혔다
init · journald · resolved · systemd --user
buff/cache 2.4 G → 2.8 G 부팅하며 ext4.vhdx 에서 파일을 읽었다
available 2.6 G → 2.6 G 늘어난 게 캐시라 여유는 그대로다
VM 안에서 실제로 일어난 일은 "캐시가 0.4G 늘었다"가 거의 전부다. Ubuntu 배포판 자체가 무거운 것을 띄우지 않아서 used는 눈에 띄게 안 늘었고, available도 그대로다.
그런데 Vmmem은 1.3GB 올랐다
게스트는 0.4G만 늘었는데 Vmmem은 그 세 배가 넘게 올랐다. 두 숫자가 재는 대상이 다르기 때문이다.
게스트 회계 프로세스가 요구해서 받아 둔 양 used + cache = 5.3G → 5.7G
Vmmem 그중 지금 물리 RAM 에 올라와 있는 양 2.5GB → 3.8GB
게스트가 5.7G를 쥐고 있다고 계산해도 물리 RAM에는 3.8GB만 있다. 나머지는 물리 RAM 밖에 나가 있다.
그리고 vmmem에 대한 배정은 고정이 아니다.
VM 이 한가하면 Windows 가 물리 RAM 배정을 줄인다 Ubuntu 켜기 전 2.5 GB
VM 이 활발해지면 배정을 늘린다 Ubuntu 켠 뒤 3.8 GB
Ubuntu 부팅은 파일을 대량으로 읽는 작업이다. 한가하던 VM이 갑자기 활발해지자 Windows가 vmmem에 배정을 늘렸다.
늘어난 1.3GB의 내역은 위 네 숫자에서 그대로 나온다.
켜기 전 게스트 보유 5.3 G − 물리 배정 2.5 GB = 물리 밖 2.8 G
켠 뒤 게스트 보유 5.7 G − 물리 배정 3.8 GB = 물리 밖 1.9 G
물리 밖이 0.9G 줄었다
Vmmem 증가 1.3 GB = 새로 요구한 0.4 G + 밖에서 되돌아온 0.9 G
증가분의 절반 이상이 새로 쓴 것이 아니다. 원래 물리 밖에 있던 몫이 다시 올라온 것이고, 그만큼 Windows 쪽 여유가 줄었다.
그래서 표를 이렇게 읽는다
게스트 세 줄 VM 안에서 무엇이 얼마나 쓰는지
Vmmem 줄 Windows 가 그 VM 에 물리 RAM 을 얼마나 내주고 있는지
두 줄이 같은 것을 재지 않으므로 증가분도 같지 않다. 이 표에서 읽을 것은 "Ubuntu를 켜니 Windows 쪽에서 1.4GB가 빠졌다" 하나다.
Vmmem 밖에 나가 있던 그 몫이 어디에 있었는지는 뒤에서 다시 나온다.
여기까지가 아무것도 안 하고 있을 때의 값이다
GitLab 이 떠 있고 Ubuntu 를 켰다. 그게 전부다
게스트 available 2.6 G
Windows 물리 여유 4.1 GB
실제 작업은 여기에 kubectl·git·빌드가 올라가고, GitLab이 clone·push를 처리하고, Chrome과 VS Code가 얹힌 상태다.
2. 증상 — 작업하다 하나씩 죽었다
작업을 하려면 넷을 켠다.
GitLab Docker Desktop 이 띄운 컨테이너. 저장소와 MR 이 여기 있다
Ubuntu 배포판 kubectl · kubeseal. 노트북 k3s 클러스터를 만진다
Chrome GitLab · Proxmox · Grafana · ArgoCD 화면을 띄운다
VS Code Claude Code 와 문서 작업
2.1 작업 중에 하나씩 멈추거나 다시 떴다
Chrome 탭이 비워진다 다시 열면 처음부터 불러온다
VS Code 가 통째로 다시 뜬다 다시 뜨는 화면에 OOMKilled 가 찍힌다
kubectl 이 갑자기 안 먹는다 wsl -l -v 를 보면 Ubuntu 가 Stopped 로 바뀌어 있다
GitLab 화면이 안 열린다 docker ps 에 gitlab 이 없다
Docker Desktop 이 아예 시작을 못 한다
규칙이 없었다. 어떤 날은 Chrome만 날아가고, 어떤 날은 Ubuntu가 통째로 Stopped가 되고, 어떤 날은 Docker Desktop이 시작조차 못 했다.
2.2 작업 관리자를 열어 보니 메모리가 차 있었다
메모리 80–90 퍼센트
상위 셋 Vmmem · Chrome · VS Code
작업을 이어 갈수록 셋이 계속 올랐다. Chrome은 탭을 열수록, VS Code는 창과 확장이 늘수록, Vmmem은 GitLab이 일할수록 커졌다.
2.3 메모리가 꽉 차서 하나씩 죽는 것으로 봤다
증상과 숫자와 에러 문구가 같은 방향을 가리켰다.
화면에 OOMKilled 가 찍혔다 Out Of Memory — 글자 그대로 메모리 부족이다
메모리가 80퍼센트를 넘어 있었다
제일 많이 먹는 셋이 계속 올랐다
물리 램이 모자라서 순서대로 밀려나 죽는다고 결론지었다.
2.4 그래서 램을 늘리기로 했다
현재 DDR3 4GB × 4 = 16GB 슬롯 넷이 전부 차 있다
교체 후 8GB × 2 + 4GB × 2 = 24GB
슬롯이 비어 있지 않아 추가가 아니라 교체다. 4GB 두 장을 빼고 8GB 두 장을 넣는 것으로 주문을 넣었다.
보드 Gigabyte P67A-UD3R-B3 슬롯 4개 · 최대 32GB · DDR3
CPU i7-2600K 4코어 8스레드
BIOS F9 (2012-03) 8GB 모듈을 못 잡던 초기 리비전이 아니다
모듈 DDR3 8GB PC3-12800 240핀 Unbuffered DIMM
2.5 램이 오기 전에 로그를 한 번 더 봤다
주문은 넣었지만 무엇이 무엇을 죽였는지는 여전히 설명할 수 없었다. 그래서 넷을 전부 띄워 메모리를 채우고, 죽는 순간의 기록을 남겼다.
GitLab 컨테이너를 띄운다
Ubuntu 배포판을 켠다
Chrome 으로 GitLab · Grafana · ArgoCD 를 연다
VS Code 를 띄운다
그 상태에서 GitLab 에 clone · push 를 걸어 부하를 준다
그리고 죽었다. 이번에는 남은 기록이 있었다.
3. 로그가 진단과 안 맞았다
3.1 GitLab — SIGKILL을 받았다는 것까지만 나왔다
죽은 직후의 컨테이너를 그대로 조회했다. docker ps는 이름과 상태를 한 줄로 요약해 주는 데 그치지만, docker inspect는 그 컨테이너의 설정과 상태를 전부 꺼내 준다. 지워지지 않고 Exited로 남아 있으면 죽은 컨테이너도 조회된다.
그냥 치면 JSON이 200줄 넘게 나오므로 --format으로 넷만 뽑았다.
docker inspect gitlab --format "restart={{.HostConfig.RestartPolicy.Name}} memlimit={{.HostConfig.Memory}} oomkilled={{.State.OOMKilled}} exit={{.State.ExitCode}}"
restart=unless-stopped memlimit=0 oomkilled=false exit=137
넷을 같이 뽑은 이유는 앞의 둘과 뒤의 둘이 성격이 다르기 때문이다. HostConfig는 컨테이너를 만들 때 준 설정이라 안 변하고, State는 마지막 종료 결과라 죽을 때마다 갱신된다. "내가 뭘 걸어 뒀나"와 "실제로 어떻게 끝났나"를 나란히 놓아야 뒤의 이야기가 보인다.
exit=137 — 강제 종료됐다는 것까지만 알려준다
리눅스에서 신호로 종료된 프로세스의 종료 코드는 128 + 신호번호다. 137은 128 + 9이고 9번 신호가 SIGKILL이니, 강제 종료 신호를 받고 끝났다는 뜻이다.
거기까지다. 누가 그 신호를 보냈는지는 안 알려준다.
oomkilled=false — 판정할 경로가 없었다
메모리 부족으로 죽었다면 이 값이 true여야 할 것 같은데 아니었다. memlimit=0이 이유다.
도커는 컨테이너마다 메모리 한도를 걸 수 있는데, 안 걸면 0이 되고 한도 없음이다. 그리고 도커가 true를 찍는 것은 자기가 건 한도를 넘었을 때뿐이라, 한도가 없으면 그 판정 자체가 성립하지 않는다.
SIGKILL이 오는 길이 여럿인데 그중 하나만 도커가 판정한다.
① 컨테이너가 자기 한도를 넘었다 cgroup 이 죽인다 OOMKilled=true 메모리 때문
② VM 전체 메모리가 바닥났다 리눅스 커널이 골라 죽인다 OOMKilled=false 메모리 때문
③ VM · 엔진이 내려갔다 그 위의 것이 전부 끌려간다 OOMKilled=false 원인 미상
④ 사람이 docker kill 을 쳤다 OOMKilled=false 메모리 무관
memlimit=0이면 ①이 아예 일어날 수 없다. 그래서 이 값은 ①만 배제할 뿐 나머지에 대해서는 아무것도 말해 주지 않는다.
여기까지 알아낸 것
알아낸 것 SIGKILL 을 받고 끝났다
① (컨테이너 한도 초과) 은 아니다 — 한도를 안 걸었으니까
못 알아낸 것 ②③④ 중 무엇인지
메모리 때문인지조차 이 기록으로는 모른다
"메모리가 꽉 차서 죽었다"는 것은 증상을 보고 세운 짐작이었고, 기록은 그것을 확인해 주지 않았다.
한도를 걸어 뒀다면 true/false 하나로 ①인지 아닌지가 갈렸을 것이다. 한도는 제한이자 진단 도구인데 안 걸어 둬서 다른 기록을 더 뒤져야 했다. 어디에 어떻게 거는지는 뒤에서 다룬다.
그래서 Docker Desktop 쪽 기록을 봤다.
3.2 Docker Desktop — 시작조차 못 하고 wsl.exe가 죽었다
GitLab을 다시 띄우려고 Docker Desktop을 켰다. 그런데 이번엔 앱이 시작조차 못 하고 에러창을 띄웠다.
running wslexec: DockerDesktop/Wsl/ExecError:
wsl.exe -d docker-desktop -u root -e wsl-bootstrap run ...
exit status 0xc00000fd
0xc00000fd — 스택을 늘리지 못했다는 뜻이다
0xc00000fd = STATUS_STACK_OVERFLOW
스택은 프로그램이 함수를 부를 때 쓰는 메모리 영역이다.
함수를 부른다 그 함수의 지역 변수와, 끝나고 돌아갈 주소가 스택에 쌓인다
함수가 끝난다 그만큼 걷힌다
깊이 들어간다 함수 안에서 함수를 부르면 계속 쌓인다
처음부터 크게 잡아 두면 낭비라, 작게 시작해서 깊이 들어갈수록 늘려 간다. 그 늘리기가 실패하면 이 코드가 난다.
스택도 메모리다. 늘린다는 것은 곧 Windows에 메모리를 더 달라고 요청하는 것이고, 그 요청이 거절되면 이 코드가 난다.
죽은 대상이 wsl.exe였다
GitLab도 아니고 엔진도 아니다. wsl.exe는 배포판을 켜는 Windows 쪽 명령이고, 컨테이너 메모리와는 상관이 없다. GitLab이 아무리 커져도 이 명령이 죽을 일은 아니다.
로그를 순서대로 읽으면 어디서 터졌는지 나온다
wsl-bootstrap은 Docker Desktop이 docker-desktop 배포판 안에서 돌리는 준비 프로그램이다. 엔진이 뜰 환경을 만드는 일을 순서대로 한다.
componentsVersion.json 없음 [W] 경고. 첫 부팅이면 정상
detected existing ext4 file system 데이터 디스크를 찾았다 (이미지 · 볼륨)
docker-desktop.iso is present in cache 엔진 이미지가 이미 있다
starting linuxkit container with unshare 엔진을 격리해서 띄운다
Restoring existing exposed ports 전에 열려 있던 포트를 복원한다
starting cross-distro routing service 배포판끼리 통신하는 경로를 연다
tcp forward 0.0.0.0:2424 → 172.18.0.2:22
tcp forward 0.0.0.0:8929 → 172.18.0.2:8929
← 여기서 exit 0xc00000fd
마지막 두 줄이 GitLab 컨테이너의 포트를 Windows 쪽으로 내보내는 작업이다.
2424 · 8929 docker-compose.yml 에 적어 둔 포트. SSH 와 HTTP
172.18.0.2 GitLab 컨테이너가 받은 IP
GitLab은 이미 떠서 IP까지 받은 상태였다. restart: unless-stopped가 걸려 있어 엔진이 뜨자마자 따라 뜬 것이고, 그 마지막 연결 작업 중에 wsl.exe가 죽었다.
wsl.exe가 죽으면 그 밑이 전부 끌려간다
wsl.exe 가 죽는다
→ WSL2 VM 이 내려간다
→ docker-desktop 배포판이 내려간다 → gitlab 컨테이너도 끝난다
→ Ubuntu 배포판도 같이 내려간다
GitLab에 SIGKILL을 보낸 것이 무엇인지가 여기서 갈린다. 컨테이너가 자기 한도를 넘은 것도, VM 안에서 리눅스 커널이 골라 죽인 것도 아니었다. VM 자체가 내려가면서 그 위의 것이 전부 끝난 것이다.
작업 중에 kubectl이 갑자기 안 먹고 wsl -l -v에 Ubuntu가 Stopped로 바뀌어 있던 것도 같은 이유였다. Ubuntu 쪽에서 뭘 잘못한 게 아니라 Docker 쪽 사고에 같이 휩쓸린 것이다.
질문이 옮겨진다
전 GitLab 이 왜 죽었나
후 wsl.exe 가 스택을 늘리려는 요청은 왜 거절됐나
문제가 리눅스 안이 아니라 Windows 쪽에 있다. 그러면 다음으로 볼 것은 하나다 — 그때 Windows에 메모리가 없었나.
3.3 물리 메모리는 남아 있었다
요청이 거절됐다면 물리 RAM이 바닥나 있어야 말이 된다. 그때 값을 봤다.
Get-CimInstance Win32_OperatingSystem | ForEach-Object {
"물리 {0:N1}GB / 여유 {1:N1}GB" -f ($_.TotalVisibleMemorySize/1MB), ($_.FreePhysicalMemory/1MB) }
물리 16.0GB / 여유 6.6GB
6GB 넘게 남아 있었다. 메모리가 없어서 못 준 것이 아니다.
3.4 그래서 남은 것
wsl.exe가 죽은 순간에 한 일은 하나였다. 스택을 한 칸 더 쓰려고 Windows에 "메모리를 조금만 더 달라"고 한 것이다. Windows는 그것을 거절했고, 그래서 STATUS_STACK_OVERFLOW로 끝났다.
① 물리 메모리는 6.6GB 남아 있었다 메모리가 없어서 못 준 것이 아니다
② 그런데 그 요청은 거절됐다 있는데도 안 준 것이다
주문까지 넣은 진단이 여기서 무너졌다. 램을 24GB로 늘려도, 물리가 남아 있는데 거절하는 그 무언가가 그대로면 같은 일이 또 난다.
Windows 는 물리 RAM 이 남아 있어도 메모리 요청을 거절할 수 있다
그렇게 만드는 다른 한도가 있다
그 한도가 무엇인지 찾기 시작했다.
4. 진짜 원인 — 커밋 한도
작업 관리자 성능 탭을 열었다. 프로세스 목록이 프로그램별로 보여주는 것과 달리, 여기는 Windows 쪽 메모리를 통째로 보여준다.

사용 중 (압축) 프로세스들이 쥐고 있는 물리 메모리. 괄호는 그중 압축해 눌러 담은 몫
사용 가능 지금부터 새 프로그램이 받을 수 있는 양
캐시됨 디스크에서 읽어 둔 사본. 필요하면 버린다
커밋됨 ← 이것만 성격이 다르다 ★
페이징 풀 커널이 쓰는 몫 중 디스크로 밀어낼 수 있는 것
비페이징 풀 커널이 쓰는 몫 중 항상 물리에 있어야 하는 것 (드라이버 등)
사용된 슬롯 메모리 슬롯이 몇 개 차 있나
free -h와 나란히 놓아 보면
VM 안을 볼 때 쓴 명령이 free -h였다. 같은 "메모리 장부"인데 재는 대상이 다르다 —
이쪽은 VM 안(total 5.8Gi는 .wslconfig의 memory=6GB에서 커널 몫을 뺀 값)이고,
성능 탭은 Windows 전체(물리 16.0GB)다.
아래 값은 다른 시점에 잰 것이라 위 성능 탭 숫자와 짝이 맞지 않는다. 여기서 볼 것은 값이 아니라 칸 이름이다.
wsl -d Ubuntu -- free -h
total used free shared buff/cache available
Mem: 5.8Gi 3.2Gi 98Mi 98Mi 2.8Gi 2.6Gi
Swap: 4.0Gi 424Ki 4.0Gi
칸끼리 대응시키면 이렇다.
used↔사용 중— 프로세스가 실제로 쥐고 있는 양buff/cache↔캐시됨— 디스크에서 읽은 파일을 RAM에 남겨 둔 사본이다. 원본이 디스크에 그대로 있어 언제든 버려도 되고, 그래서available·사용 가능안에 이미 포함돼 있다available↔사용 가능— 지금부터 새로 쓸 수 있는 양Swap↔페이지파일— RAM이 모자랄 때 안 쓰는 것을 내려두는 디스크 자리다. 캐시와 방향이 반대라 버릴 수 없다 — RAM에만 있던 내용이라 디스크에 써 두지 않으면 사라진다. 다만 이Swap 4.0Gi는 VM 안 리눅스의 것(.wslconfig의swap=4GB)이고, Windows 페이지파일과는 별개다커밋됨↔ 대응하는 칸이 없다 ★
free -h에는 커밋에 해당하는 칸이 없다
리눅스는 요청을 일단 받아준다. 예약 총량으로 벽을 세우지 않고, 실제로 물리가 바닥나면 그때 OOM killer가 프로세스를 골라 죽인다.
Windows는 반대다. 예약 단계에서 한도를 넘으면 그 자리에서 거절한다. 죽이는 대신 요청이 실패하고, 요청한 쪽이 알아서 무너진다.
리눅스 일단 받는다 → 물리가 바닥나면 → 누군가를 죽인다 OOM killer 가 있다
Windows 한도를 넘으면 → 그 자리에서 거절 → 요청한 쪽이 실패한다 OOM killer 가 없다
free -h만 봐서는 이번 원인이 안 잡히는 이유가 여기 있다. 문제를 만든 항목이 리눅스 쪽 화면에는 아예 없다.
커밋됨만 분모가 다르다
사용 중 · 사용 가능 합치면 물리 RAM 이 된다 9.4 + 6.6 = 16.0 GB
커밋됨 분모가 물리 RAM 이 아니다 15.5 / 17.9 GB
물리 여유 6.6 GB
커밋 여유 2.4 GB
분모가 물리보다 크다는 것은 물리와 다른 것을 재고 있다는 뜻이고, 여유도 물리 쪽과 따로 논다. 물리가 요청을 막은 것이 아니라면 남는 후보는 이쪽이다.
그래서 둘을 봐야 했다 — 커밋이 무엇이고, 왜 한도가 하필 17.9GB인가.
4.1 커밋이 무엇인가
프로그램이 메모리를 요청하면 Windows는 물리 RAM을 바로 주지 않는다. "이만큼은 보장한다"고 예약만 해 둔다.
1GB 를 요청한다 예약 +1GB 물리 RAM 은 아직 안 썼다
100MB 를 실제로 쓴다 물리 +100MB 예약은 여전히 1GB
나머지 900MB 안 쓰고 있는데도 계속 예약돼 있다
안 쓰고 있어도 다른 프로그램이 그 자리를 못 쓴다. Windows가 이미 약속해 뒀기 때문이다.
한 번에 다 예약하는 것도 아니다. 탭을 열고 파일을 열 때마다 조금씩 더 요청하고, 프로그램이 끝나면 그 몫이 통째로 풀린다. 커밋은 작업하는 내내 오르내리는 값이다.
지금 돌고 있는 모든 프로그램의 예약을 전부 더한 것이 커밋이고, 그 합이 넘을 수 없는 선이 커밋 한도다.
커밋됨 15.5 / 17.9 GB
커밋 한도
한도가 물리 RAM보다 크다
물리 RAM 16.0 GB
커밋 한도 17.9 GB 물리보다 1.9GB 더 크다
없는 메모리를 약속해 둔 셈이다. 그게 가능한 이유가 페이지파일이고, 이 1.9GB가 곧 페이지파일 크기다.
4.2 페이지파일이 무엇인가
약속을 지키려면 실제로 내줄 자리가 있어야 한다. 물리 RAM이 비어 있으면 거기서 주고, 다 찼으면 페이지파일에서 자리를 만든다.
페이지파일은 디스크에 만들어 둔 파일이고, 물리 RAM 자리를 돌려쓰게 해 주는 임시 보관소다.
물리 RAM 16GB 가 다 찼는데 새 프로그램이 1GB 를 달라고 한다
① Windows 가 지금 안 쓰는 1GB 를 고른다 예: 30분째 안 만진 Chrome 탭
② 그 내용을 페이지파일에 써 둔다 디스크로 옮긴다
③ 비워진 물리 RAM 1GB 를 새 프로그램에게 준다
④ 나중에 그 Chrome 탭을 다시 보면 디스크에서 읽어 다시 올린다. 느리다
리눅스의 swap과 같은 역할이다. 약속한 총량이 동시에 물리에 올라와 있을 필요가 없어지므로, 물리 16GB로 그보다 큰 총량을 약속할 수 있다. 페이지파일이 한도에 그대로 더해지는 것이 이 때문이다.
대가는 속도다. 디스크로 내려간 것을 다시 쓰려면 읽어 올려야 하고, RAM보다 훨씬 느리다.
크기는 보통 Windows에 맡긴다
Windows 기본값이 자동 관리이고, 그때 Windows가 하는 일이 이렇다.
크기 결정 물리 메모리 · 커밋 총량 · 크래시 덤프 설정을 보고 정한다
최소 RAM ÷ 8 (최대 32GB)
확장 커밋이 한도의 90% 를 넘으면 늘린다
최대 물리 메모리의 3배 또는 4GB 중 큰 값. 단 그 볼륨 크기의 1/8 이하
얼마로 잡아야 하는지에 대해 공식 문서는 고정 비율을 주지 않는다.
페이지파일 크기는 크래시 덤프 설정과 커밋 총량의 피크에 달려 있고, 둘 다 시스템마다 다르다. 그래서 페이지파일 크기도 시스템마다 다르며 일반화할 수 없다.
— How to determine the appropriate page file size for 64-bit versions of Windows
자동 관리는 그 판단을 Windows가 대신해 주는 것이다. 커밋이 차오르면 늘리고 한가해지면 줄이니, 내가 피크를 재서 숫자를 정할 필요가 없다.
대신 디스크를 먹는다
페이지파일은 실제로 디스크에 만들어지는 파일이다. 8GB로 잡으면 그 드라이브에서 8GB가 사라지고, 자동으로 두면 필요할 때 더 커지므로 그만큼 더 먹는다.
그래서 "디스크 용량 확보"를 검색하면 페이지파일을 줄이거나 끄라는 방법이 나온다.
자동 관리를 끈다
C: 를 "페이징 파일 없음" 으로 바꾼다 C 에서 그만큼 용량이 돌아온다
필요하면 다른 드라이브에 작게 만든다
공간은 실제로 늘어난다. 대신 커밋 한도가 그만큼 깎인다.
그래서 설정을 열어 봤다
뺄셈으로 나온 페이지파일 크기가 1.9GB(커밋 한도 17.9 − 물리 16.0)였다. 자동 관리였다면 커밋이 한도에 닿아 가는 동안 늘어났어야 한다. 안 늘어났다는 것은 누군가 수동으로 크기를 고정해 뒀다는 뜻이다.
어떻게 잡혀 있는지 보러 갔다.
4.3 고정 페이징 파일 크기가 2GB로 고정돼 있었다
Win + R → sysdm.cpl → 고급 탭 → 성능 설정 → 고급 탭 → 가상 메모리 변경\



자동 관리 체크가 꺼져 있다 크기를 Windows 가 아니라 내가 정하고 있다
C: 없음 232GB 짜리 드라이브에 페이지파일이 아예 없다
E: 512 - 2048 여기 하나뿐이고 최대가 2048MB 다
현재 총 크기 1960MB
1960MB가 뺄셈으로 나온 그 1.9GB다. 예상한 대로였다.
두 줄이 겹쳐서 천장이 고정됐다
자동 관리 해제 크기를 정하는 주체가 Windows 에서 나로 바뀐다
최대 2048MB 그렇게 내가 넣어 둔 천장이 2GB 다
이 둘은 나란한 두 원인이 아니라 하나를 두 각도에서 말한 것이다. 체크를 풀지 않으면 크기 칸이 잠겨서 값을 넣을 수 없고, 값을 넣어 두면 Windows는 그 위로 못 올린다(내 데스크탑 상황).
커밋 한도 = 물리 16.0GB + 페이지파일 1.9GB = 17.9GB
이 값이 뒤의 모든 거절을 만든다.
이 설정을 언제 했는지도 기억이 났다. 예전에 C 드라이브 용량이 모자라 "디스크 용량 확보"를 찾아보고 그대로 따라 한 것이다. 그때는 페이지파일이 커밋 한도를 정한다는 것을 몰랐다.
4.4 왜 그게 0xc00000fd 를 만드나
여기까지 나온 것을 모으면 이렇다.
4.1 커밋 = 프로그램들이 약속받아 둔 총량. 커밋 한도 = 그 합이 넘을 수 없는 선
4.2 커밋 한도 = 물리 RAM + 페이지파일
4.3 자동 관리가 꺼진 채 페이지파일이 2GB 로 고정돼 있었다 → 한도 17.9GB
문제의 상황에 물리적인 램 사용율과 커밋률에 대한 숫자가 이랬다.
사용 중 9.4 GB + 사용 가능 6.6 GB = 16.0 GB 물리는 이렇게 나뉘어 있다
커밋됨 15.5 / 17.9 GB 약속은 이만큼 나가 있다
물리와 커밋은 다른 장부다
물리 장부 지금 실제로 어디에 무엇이 올라와 있나
커밋 장부 앞으로 누구에게 얼마를 주기로 했나
약속(15.5GB)이 실제 사용(9.4GB)보다 크다. 차이 6.1GB는 약속만 받고 아직 안 쓴 몫이고, 지금 어디에도 실체가 없다. 장부에만 적혀 있다.
그래서 사용 가능 6.6GB를 새로 못 준다
약속은 했는데 아직 안 쓴 몫 6.1 GB (커밋됨 − 물리 사용 중 = 15.5 − 9.4)
그것이 나중에 쓰이면 들어갈 자리 사용 가능 6.6 GB
사용 가능 6.6GB는 아무나 써도 되는 자리가 아니라, 이미 약속된 6.1GB가 들어올 자리다.(왜 6.1GB? 커밋된 용량 15.5에서 물리적 사용중인 용량 6.4를 빼면 나오는 값 - 미리 쓴다고 약속된 값 = 커밋)
여기에 새 요청까지 받아주면 같은 자리를 두 번 약속하는 셈이 된다. Windows는 그것을 안 한다.
빼고 남는 것이 실제로 새로 줄 수 있는 양이다.
사용 가능 6.6 GB
− 이미 약속된 몫 6.1 GB
────────────────────────
물리에서 남는 것 0.5 GB
+ 페이지파일 1.9 GB
────────────────────────
커밋 여유 2.4 GB ← 17.9 − 15.5 와 같다
작업 관리자가 보여주던 커밋 여유 2.4GB가 바로 이 계산의 결과다.
거기서 GitLab을 띄웠다
.wslconfig의 memory=6GB는 VM 쪽 상한이지, Windows가 그만큼 내주겠다는 보장이 아니다. VM이 커지는 만큼 Windows 커밋 장부를 그대로 먹는다.
그 상태 커밋 여유 2.4 GB
wsl 을 친다 Ubuntu 부팅으로 VM 이 커진다. 실측 Vmmem +1.3GB
→ 커밋 여유 약 1.1 GB
GitLab 까지 뜬다 컨테이너 정착만 2.9 GiB 를 요구한다
→ 남은 1.1GB 로는 못 받는다
여유가 여기서 바닥났다.
거절당한 것은 wsl.exe 였다
GitLab이 요청했다가 거절당한 것이 아니다. 여유를 먹은 쪽과 거절당한 쪽이 다르다.
GitLab 이 커진다 → VM 이 Windows 에 커밋을 더 요구한다 → 여유가 바닥난다
↓
wsl.exe 가 스택 커밋을 요청한다 → 거절 → 0xc00000fd
스택은 처음부터 크게 잡지 않고 깊이 들어갈 때마다 새 페이지를 커밋해 늘려 간다. 그 커밋이 거절되면 Windows는 STATUS_STACK_OVERFLOW로 보고한다. 요청이 크든 작든 상관없다 — 여유가 모자라면 똑같이 거절이다.
그리고 wsl.exe가 죽으면 VM이 통째로 내려가면서 그 위의 배포판과 컨테이너가 전부 끝난다. GitLab이 oomkilled=false에 exit 137만 남긴 것이 이래서다. 자기 한도를 넘은 것이 아니라 밑이 꺼진 것이다.
그래서 어떤 날은 되고 어떤 날은 죽었다
커밋은 탭을 열고 닫을 때마다 오르내리는데 한도는 17.9GB에 고정돼 있다. 여유가 2.4GB밖에 없는 상태에서는, 그날 켜 둔 것이 조금만 달라도 GitLab이 들어가기도 하고 안 들어가기도 한다.
같은 작업인데 결과가 갈리던 것이 이 폭이었다.
4.5 사슬 전체
① 페이지파일을 E 드라이브에 최대 2048MB 로 고정해 뒀다 자동 관리 해제 상태
② 커밋 한도 = 물리 16.0GB + 1.9GB = 17.9GB
③ 크롬 · VS Code · Windows 가 15.5GB 를 약속받아 뒀다 여유 2.4GB
④ GitLab 을 띄우자 VM 이 커밋을 더 요구했다 여유가 바닥난다
⑤ 그다음 커밋 요청이 거절됐다 물리는 6.6GB 남았지만 한도가 먼저 막았다
⑥ 그 요청을 한 쪽이 wsl.exe 의 스택이었다 0xc00000fd
⑦ wsl.exe 가 죽고 VM 이 통째로 내려갔다 Ubuntu 도 GitLab 도 같이
⑤에서 거절당하는 쪽은 그때그때 다르다. Chrome이 요청했으면 탭이 비워지고, VS Code면 통째로 다시 뜬다. 날마다 죽는 것이 달라 규칙이 없어 보이던 것이 이것이었다 — 원인은 하나인데 걸리는 쪽이 매번 달랐다.
문제는 요구가 아니라 천장이었다
요구 크롬 탭 · VS Code 확장 · VM. 작업하는 내내 오르내린다
천장 자동 관리를 꺼 두고 2048MB 로 고정해 뒀다. 안 움직인다
Windows에서 커밋이 물리 RAM을 넘는 것은 사고가 아니라 기본 동작이다. 프로그램은 언제나 실제 쓸 양보다 크게 예약하고, 그 초과분을 받아주라고 페이지파일이 있다. 커밋이 15.5GB까지 오른 것 자체는 정상이다.
문제는 천장이 물리보다 1.9GB밖에 높지 않았던 것이고, 그것은 램이 모자라서가 아니라 내가 그렇게 설정해 뒀기 때문이다.
천장을 올리는 방법은 둘이고, 둘 다 유효하다.
램을 24GB 로 늘린다 한도 = 24 + 1.9 = 25.9 GB 8GB 오른다. 부품값이 든다
페이지파일 상한을 올린다 한도 = 16 + 12 = 28.0 GB 12GB 오른다. 돈이 안 든다
다만 막힌 곳이 천장이라면 먼저 되돌릴 것은 내가 잘라 놓은 쪽이다. 램은 그다음이다.
5. 고친 과정
5.1 페이지파일을 다시 세웠다
두 번에 나눠 했다. 먼저 C:에 8GB를 잡아 한도부터 올려 죽는 것이 멈추는지 봤고, 멈춘 것을 확인한 뒤 자리를 E:로 옮기면서 12GB로 키웠다.
고치기 전 C: 없음 E: 512 - 2048 한도 17.9 GB
1차 C: 8192 - 16384 E: 없음 한도 24.0 GB
2차 C: 없음 E: 12288 - 16384 한도 28.0 GB
1차만으로 GitLab이 죽지 않고 계속 떠 있었다. 원인을 제대로 짚었다는 것이 여기서 확인됐다.
다만 그동안 커밋이 최고 20.4GB까지 올라갔다. 한도 24.0GB에 3.6GB까지 붙은 것이라, 2차에서 자리를 옮기면서 크기를 키웠다.
Win + R → sysdm.cpl → 고급 탭 → 성능 설정 → 고급 탭 → 가상 메모리 변경
자동 관리 체크 해제 그대로 둔다
C: 페이징 파일 없음
E: 사용자 지정 크기. 처음 12288 MB / 최대 16384 MB

값을 넣고 설정(S)을 눌러야 목록에 반영된다. 그 상태로 확인하고 재부팅해야 적용된다.
왜 C:가 아니라 E:인가
디스크 0 Samsung SSD 850 EVO 120GB → E: 111GB 중 35.5GB 여유
디스크 1 WDC WDS250G2B0A (WD Blue) → C: 232GB 중 16.8GB 여유
C:의 16.8GB는 이미 8GB 페이지파일이 올라간 상태의 여유다. 여기에 12GB를 두면 12.8GB가 남고, 나중에 16GB까지 자라면 8.8GB가 된다. 232GB짜리 시스템 드라이브에 남길 여유로는 빠듯하다.
E:에 두면 C:의 여유가 24.8GB로 돌아오고, E:에도 19.5GB가 남아 나중에 더 키울 자리가 있다.
성능상으로도 불리하지 않다. 둘 다 SATA SSD라 느려질 이유가 없고, 물리 디스크가 서로 달라 OS의 디스크 작업과 페이징이 같은 디스크를 놓고 다투지 않는다.
왜 자동 관리가 아니라 수동인가
자동 관리로 두면 Windows가 최대치를 물리의 3배 또는 4GB 중 큰 값, 단 그 볼륨 크기의 1/8 이하로 잡는다. E:에 대입하면 이렇게 된다.
물리의 3배 48.0 GB
볼륨의 1/8 111GB ÷ 8 = 13.9 GB ← 둘 중 작은 쪽이 천장이 된다
E:에 자동 관리를 걸면 최대가 13.9GB에서 막힌다. 수동으로 16384를 넣는 쪽이 천장이 더 높다.
왜 12288 - 16384 인가
관측된 커밋 피크 20.4 GB GitLab + Ubuntu + Chrome + VS Code 를 다 켠 상태
물리 16.0 GB
최소로 필요한 것 20.4 − 16.0 = 4.4 GB
처음 12288 한도 28.0GB 로 부팅한다. 피크 대비 7.6GB 여유
최대 16384 모자라면 32.0GB 까지 자란다
처음 크기를 크게 잡으면 커밋이 몰릴 때 파일이 자라기를 기다리지 않아도 되고, 파일이 한 덩어리로 잡혀 조각나지 않는다. 대가는 E:에서 12GB가 계속 나가 있는 것 하나다.
5.2 커밋 한도가 28.0GB가 됐다
재부팅하고 같은 자리를 다시 봤다.
고치기 전 고친 후
──────────────────────────────────────────────────────
페이지파일 E: 512 - 2048 E: 12288 - 16384
커밋 한도 17.9 GB 28.0 GB ← 바뀐 것은 이 줄뿐이다
물리 RAM 16.0 GB 16.0 GB 한 장도 안 바꿨다
커밋 총량이 비슷한 시점끼리 견주면 여유가 이렇게 갈린다.
고치기 전 커밋 15.5 / 17.9 GB 여유 2.4 GB
고친 후 커밋 15.1 / 28.0 GB 여유 12.9 GB
켜 둔 것이 같아서가 아니라 한도가 달라서 벌어진 차이다. 커밋을 만든 쪽은 그때나 지금이나 Chrome·VS Code·Windows이고, 바꾼 것은 페이지파일 한 줄이다.
정리
증상 하루에 열 번 가까이 뭔가가 죽었다
처음 진단 메모리 80퍼센트. 물리 램 부족으로 보고 8GB 두 장을 주문했다
안 맞은 기록 oomkilled=false · 0xc00000fd · 물리 여유 6.6GB
진짜 원인 커밋 한도 17.9GB. 페이지파일을 2GB 로 고정해 둔 설정이 그대로 남아 있었다
고친 것 페이지파일 12GB. 한도 28.0GB. 커밋 여유 2.4 → 12.9GB
증상이 가리키는 곳과 원인이 있는 곳이 달랐다. 메모리가 80퍼센트라는 것은 사실이었지만 그것이 죽은 이유는 아니었고, 죽은 이유는 같은 화면의 다른 칸에 있었다.
그 칸을 읽을 줄 몰라서 램을 주문했다.
그래서 램 주문은 취소했다
주문한 것 DDR3 8GB × 2 4GB 두 장을 빼고 넣을 생각이었다
근거 메모리 80퍼센트. 뭔가가 계속 죽는다
그 근거가 기록과 안 맞았다. 물리 RAM은 6.6GB가 남은 상태에서 요청이 거절됐고, 페이지파일만 바꾸니 커밋이 비슷한 시점끼리 견줘 여유가 2.4GB에서 12.9GB가 됐다.
램이 한 일이 없다.
그렇다고 안 사도 된다는 뜻은 아니다
물리 16GB는 그대로다. 천장을 올린 것이지 RAM을 늘린 것이 아니다. 그래서 언제 사야 하는지를 미리 숫자로 정해 뒀다.
① 천장을 더 올려도 또 닿는다
지금 16 + 12 = 28.0 GB 필요하면 16 까지 자라 32.0 GB
더 올린다 최대를 24576 으로 16 + 24 = 40.0 GB. E: 여유로 가능하다
아직 페이지파일 쪽에 올릴 자리가 남아 있다. 그것까지 하고도 거절이 나면 물리가 답이다.
② 안 죽는데 느려진다
천장이 낮다 요청이 거절된다 → 죽는다 천장을 올리면 해결된다
물리가 모자라다 요청은 통과한다 → 디스크를 오간다 → 느려진다 천장으로는 해결 안 된다
페이지파일을 40GB로 잡아도 물리 16GB를 넘는 몫은 결국 디스크를 오간다. 이것은 램 말고 답이 없다.
둘을 가르는 값
PeakUsage 하나다. 페이지파일로 실제로 얼마나 밀려났는지를 알려주는 값이고, 지금은 1MB다.
1MB 근처에 머문다 밀어낼 일이 없었다. 물리로 충분하다 → 램은 아직 필요 없다
GB 단위로 오른다 물리가 모자라 밀어내기 시작했다 → ②
이 값이 오르기 시작하는 때가 램을 다시 볼 때다.
넣는다면
지금 DDR3 4GB × 4 = 16GB 슬롯 4개가 전부 차 있다
교체 8GB × 2 + 4GB × 2 = 24GB 추가가 아니라 교체다
한도 24 + 12 = 36.0 GB 페이지파일을 안 건드려도 8GB 오른다
램을 늘렸다고 페이지파일을 따라 늘릴 이유는 없다. 물리가 커지면 밀어낼 일이 줄어들어 수요는 오히려 준다.
'HomeLab' 카테고리의 다른 글
| 노트북 홈서버 k3s 구축기 - 10. CI 와 CD (0) | 2026.08.09 |
|---|---|
| 번외 — CI 파이프라인 기록 (0) | 2026.08.09 |
| 노트북 홈서버 k3s 구축기 - 9. GitLab 세우기 (0) | 2026.08.04 |
| 노트북 홈서버 k3s 구축기 - 8. 관측 파이프라인 (0) | 2026.08.02 |
| 노트북 홈서버 k3s 구축기 - 번외. e1000e NIC hang (0) | 2026.07.29 |