Diagnosing Memory and OOM
한국어 원문으로 표시합니다.
목표
메모리 지표를 정확히 읽고, 프로세스가 실제로 붙잡은 메모리와 예약만 한 주소 공간을 구분하고, OOM Killer 가 무엇을 보고 고르는지 확인합니다.
왜 중요한가
메모리 문제의 오진 대부분은 잘못된 열을 보는 것에서 시작합니다. free 의 free 열이 아니라 available 열을 봐야 하고, top 의 VIRT 가 아니라 RES(RSS)를 봐야 합니다. OOM Killer 의 점수도 RSS 기준입니다 - 64GB 를 mmap 으로 예약만 한 프로세스는 후보조차 아닙니다. 그리고 컨테이너 안에서 free 는 호스트 전체를 보여 주므로, 진짜 상한은 cgroup 파일에서 읽어야 합니다. 이 실습의 7번이 "없으면 없다고 적어라"까지 채점하는 이유는, 현장에서도 그 파일이 있는지부터 확인하는 것이 첫 동작이기 때문입니다.
단계
/root/mem 디렉터리에서 작업합니다.
/proc/meminfo의MemTotal값을 kB 숫자만/root/mem/total_kb.txt에 적으세요.MemAvailable값을 kB 숫자만/root/mem/available_kb.txt에 적으세요.- 실제 상주 메모리(VmRSS)가 100MB 이상인 프로세스를 백그라운드로 띄우고 PID 를
/root/mem/hog_pid.txt에 적으세요. 이후 단계 내내 살아 있어야 합니다. - 그 프로세스의
VmSize와VmRSS를/root/mem/vm.txt에 다음 두 줄로 적으세요.vsize_kb=<값>rss_kb=<값>
- 그 프로세스의
oom_score_adj를500으로 설정하고, 그 뒤에 읽은oom_score값을/root/mem/oom_score.txt에 적으세요. /root/mem/topmem.sh <N>을 만드세요. RSS 상위 N개 프로세스를<rss_kb> <comm>형식으로 내림차순 출력합니다. 정확히 N줄이어야 합니다.- 이 컨테이너의 cgroup 메모리 한도를
/root/mem/limit.txt에 그대로 적으세요. 해당 파일을 읽을 수 없는 환경이면unavailable이라고 적으세요. /root/mem/memguard.sh <임계값kB>를 만드세요. RSS 가 임계값을 넘는 프로세스가 있으면over=<PID>를 한 줄씩 출력하고 종료 코드 1, 없으면ok한 줄과 종료 코드 0. 인자가 없으면 0이 아닌 코드입니다.
참고
python3 -c "import time; b=bytearray(150*1024*1024); time.sleep(9999)" &로 메모리를 실제로 붙잡을 수 있습니다./proc/<PID>/status에VmSize,VmRSS,/proc/<PID>/oom_score와oom_score_adj가 각각 있습니다.- 커널 스레드는
VmRSS항목이 없으므로 6번과 8번에서 걸러야 합니다. - 흔한 실수 1: 3번에서 메모리를 할당만 하고 쓰지 않으면 VmSize 만 늘고 VmRSS 는 그대로입니다.
- 흔한 실수 2: 5번에서
oom_score를 먼저 읽고 adj 를 나중에 바꾸면 값이 맞지 않습니다.
전체 메모리 읽기
/proc/meminfo 의 MemTotal 값을 kB 숫자만 /root/mem/total_kb.txt 에 적으세요.
/proc/meminfo 의 첫 항목입니다. 단위 kB 그대로 숫자만 적으세요.
MemAvailable 과 MemFree 구분하기
MemAvailable 값을 kB 숫자만 /root/mem/available_kb.txt 에 적으세요.
리눅스는 남는 메모리를 페이지 캐시로 씁니다. 회수 가능한 양까지 계산한 값이 따로 있습니다.
메모리를 실제로 붙잡기
실제 상주 메모리(VmRSS)가 100MB 이상인 프로세스를 백그라운드로 띄우고 PID 를 /root/mem/hog_pid.txt 에 적으세요. 이후 단계 내내 살아 있어야 합니다.
할당만 하고 건드리지 않으면 RSS 가 늘지 않습니다. 실제로 채워 넣어야 합니다. python3 로 bytearray 를 만들고 sleep 하면 됩니다.
VmSize 와 VmRSS 비교
그 프로세스의 VmSize 와 VmRSS 를 /root/mem/vm.txt 에 다음 두 줄로 적으세요.
vsize_kb=<값>rss_kb=<값>
/proc//status 에 둘 다 있습니다. 예약된 주소 공간과 실제 상주 메모리의 차이를 확인하세요.
OOM 점수 조정하기
그 프로세스의 oom_score_adj 를 500 으로 설정하고, 그 뒤에 읽은 oom_score 값을 /root/mem/oom_score.txt 에 적으세요.
/proc//oom_score_adj 에 값을 쓰면 됩니다. 올리는 것은 언제나 허용됩니다. 바꾼 뒤에 oom_score 를 읽으세요.
RSS 상위 프로세스 뽑기
/root/mem/topmem.sh <N> 을 만드세요. RSS 상위 N개 프로세스를 <rss_kb> <comm> 형식으로 내림차순 출력합니다. 정확히 N줄이어야 합니다.
/proc/*/status 의 VmRSS 를 모아 정렬합니다. 커널 스레드는 VmRSS 항목이 없습니다.
컨테이너의 진짜 한도 찾기
이 컨테이너의 cgroup 메모리 한도를 /root/mem/limit.txt 에 그대로 적으세요. 해당 파일을 읽을 수 없는 환경이면 unavailable 이라고 적으세요.
free 명령은 호스트를 보여 줍니다. 실제 상한은 cgroup 파일에 있습니다. 없으면 없다고 적으세요.
메모리 감시 스크립트
/root/mem/memguard.sh <임계값kB> 를 만드세요. RSS 가 임계값을 넘는 프로세스가 있으면 over=<PID> 를 한 줄씩 출력하고 종료 코드 1, 없으면 ok 한 줄과 종료 코드 0. 인자가 없으면 0이 아닌 코드입니다.
임계값을 인자로 받아 초과 프로세스를 보고합니다. 초과가 있으면 종료 코드 1, 없으면 ok 와 0 입니다.