cgroup v2 memory.max — 프로세스 한도는?
cgroup v2 memory.max는 해당 cgroup(과 자손)이 쓸 수 있는 메모리 하드 한도입니다. 사용량이 한도에 닿고 줄이지 못하면 그 cgroup 안에서 OOM killer가 동작합니다. 이 글은 어디에 쓰는지 · OOM 증상 · 컨테이너와의 차이만 다룹니다. 요금·제휴·창작 벤치 숫자는 없습니다.
근거는 Control Group v2 — Memory의 memory.max / memory.events / memory.high / memory.oom.group 절입니다.
어디에 쓰나?
한 줄 답: unified hierarchy 마운트 아래 해당 cgroup 디렉터리의 memory.max 파일에 바이트 단위로 씁니다. 컨트롤러는 부모의 cgroup.subtree_control에 +memory가 있어야 자식에 인터페이스가 생깁니다.
실무 순서(수동 검증용):
- cgroup2인지 확인합니다. 보통
/sys/fs/cgroup이고,/proc/self/cgroup에0::/...형태가 보입니다. - 부모에서 메모리를 자식에게 나누려면
echo +memory > …/cgroup.subtree_control합니다(이미 켜져 있으면 생략). mkdir로 자식 cgroup을 만듭니다.echo <bytes> > memory.max로 하드 한도를 겁니다. 기본값은 문서상max(무제한) 입니다.echo <PID> > cgroup.procs로 프로세스를 넣습니다. 한 번에 PID 하나입니다.
# 예: 실험용 하위 cgroup (경로는 배포에 맞게)
CG=/sys/fs/cgroup/demo-job
mkdir -p "$CG"
# 상위(여기서는 루트)에 memory가 이미 열려 있어야 함
echo 268435456 > "$CG/memory.max" # 256 MiB (바이트)
echo $$ > "$CG/cgroup.procs"
cat "$CG/memory.current" "$CG/memory.max"
문서 요지:
- 메모리양은 바이트입니다.
PAGE_SIZE에 맞지 않으면 읽을 때 올림될 수 있습니다. memory.max는 하드 한도입니다. 줄이지 못하면 cgroup 내 OOM killer가 호출됩니다. 일시적으로 한도를 넘는 경우도 있습니다.- 관리 에이전트가 먼저 개입하게 하려면 같은 문서의
memory.high(스로틀, OOM 미호출) 를 함께 봅니다. Usage Guidelines도 “주로 high로 제어하고 max는 최후 방어”에 가깝게 설명합니다. - 프로세스를 자주 옮기는 것은 비싸며, 메모리는 생성한 cgroup에 청구된 채 따라가지 않습니다(Memory Ownership).
OOM 증상은?
한 줄 답: 한도 근처·초과 시 memory.events의 max / oom / oom_kill 카운터가 증가하고, 희생 프로세스는 커널 OOM 경로로 죽습니다. memory.high만 넘으면 스로틀·리클레임이지 OOM이 아닙니다.
memory.events(비루트, hierarchical)에서 특히 볼 키:
| 키 | 의미(문서) |
|---|---|
max | 사용량이 max 경계를 넘으려 한 횟수. 직접 리클레임 실패 시 OOM 상태로 |
oom | 한도에 닿아 할당이 실패하려 한 횟수(OOM killer를 옵션으로 보지 않는 할당은 안 올림) |
oom_kill | 이 cgroup 소속 프로세스가 어떤 종류든 OOM killer에 죽은 횟수 |
oom_group_kill | group OOM 발생 횟수 |
high | high 경계를 넘어 스로틀·직접 리클레임에 들어간 횟수 |
# 이벤트·현재 사용량
cat /sys/fs/cgroup/demo-job/memory.events
cat /sys/fs/cgroup/demo-job/memory.current
# 로컬만 보려면
cat /sys/fs/cgroup/demo-job/memory.events.local
운영에서 같이 보는 신호:
- dmesg / journal에 cgroup·프로세스를 가리키는 OOM kill 로그.
- 할당 실패 — 일부 경로는 OOM killer 없이
-ENOMEM등으로 돌아갈 수 있다고 문서가 말합니다. memory.oom.group=1이면 그 cgroup(자손 포함)을 한 덩어리로 죽이거나 하나도 안 죽입니다.oom_score_adj=-1000보호 태스크는 예외입니다. OOM이 그 cgroup에서 났을 때 바깥 태스크는 죽이지 않습니다.
# 워크로드 단위로 같이 죽이기(선택)
echo 1 > /sys/fs/cgroup/demo-job/memory.oom.group
memory.high와 혼동하지 않습니다. high는 무거운 리클레임·스로틀이고 OOM을 호출하지 않으며, 극단에서는 한도를 넘을 수도 있습니다.
컨테이너와 차이는?
한 줄 답: Docker·Podman·Kubernetes의 메모리 한도는 결국 같은 cgroup v2 memory controller에 쓰입니다. 차이는 누가 디렉터리를 만들고 memory.max를 쓰느냐(런타임/오케스트레이터 vs 수동·systemd)입니다.
| 구분 | 수동 memory.max | 컨테이너 런타임 |
|---|---|---|
| 쓰기 주체 | 관리자·스크립트·systemd | dockerd / conmon / kubelet 등 |
| 경로 | /sys/fs/cgroup/... 직접 | 런타임이 만든 하위 cgroup |
| 관측 | memory.current / events | 동일 파일 + docker stats 등 래퍼 |
| 스코프 | 넣은 PID 트리 | 컨테이너 PID 1 기준 트리 |
| 부가 한도 | 직접 memory.swap.max 등 | --memory-swap / Limit 등으로 매핑 |
실무 해석:
--memory/resources.limits.memory를 켠 컨테이너는 호스트에서 해당 컨테이너 cgroup의memory.max를 보면 같은 숫자가 나옵니다(단위·반올림만 확인).- 베어 프로세스·배치 잡은 컨테이너 없이 systemd slice/
MemoryMax=또는 위 수동 절차로 같은 하드 한도를 겁니다. - 한도 “이름”만 다른 것이 아닙니다. v1의
memory.limit_in_bytes와 파일명은 달라도, v2 unified에서는memory.max가 하드 한도입니다. - 디버깅 시 컨테이너 안에서가 아니라 호스트 cgroup 경로의
memory.events를 보면 OOM이 cgroup 한도인지 전역 압력인지 가르기 쉽습니다.
# 컨테이너가 떠 있을 때(예: systemd/docker cgroup 경로 — 배포마다 다름)
# 호스트에서 해당 컨테이너 cgroup의 memory.max / memory.events를 확인
cat /sys/fs/cgroup/…/memory.max
cat /sys/fs/cgroup/…/memory.events
자주 묻는 질문
memory.high만 있으면 되나?
문서 Usage Guidelines는 high를 주된 제어로 두고, max는 줄이지 못할 때의 하드 한도·OOM 경로로 둡니다. 모니터링 에이전트가 있으면 high 우선이 자연스럽습니다.
한도를 낮추면 바로 죽나?
사용량이 이미 한도 위면 리클레임·이후 charge에서 OOM 경로가 열릴 수 있습니다. O_NONBLOCK으로 memory.max를 열면 동기 리클레임·oom-kill을 건너뛸 수 있다고 문서가 적습니다(관리 프로세스용).
프로세스를 옮기면 메모리가 따라가나?
아니요. 청구는 인스턴스한 cgroup에 남습니다. 자주 migrate하지 말라는 설계 설명이 문서에 있습니다.
루트 cgroup에 memory.max가 없다.
관례상 루트는 리소스 제어 인터페이스가 없습니다. 비루트 cgroup에 씁니다.
정리
**memory.max**는 cgroup v2 memory controller의 하드 한도이고, 줄이지 못하면 cgroup 내 OOM으로 이어집니다. 쓰기는 해당 디렉터리의 memory.max, 증상은 memory.events, 컨테이너는 같은 파일에 런타임이 대행합니다. soft 제어는 memory.high. 근거: cgroup-v2 Memory. 제휴 없음.
공식 문서는 어디인가?
- Control Group v2 — The Linux Kernel documentation — Memory:
memory.max,memory.high,memory.events,memory.oom.group, Ownership - cgroup-v2.rst (source) — 동일 문서 소스