리눅스 메모리 오버커밋: overcommit_memory 0·1·2와 CommitLimit 읽는 법

리눅스가 메모리 할당 요청을 얼마나 엄격하게 따질지 정하는 vm.overcommit_memory의 세 모드, /proc/meminfo의 CommitLimit와 Committed_AS를 읽는 법, 모드 2로 바꾸기 전에 확인할 점을 커널 문서 기준으로 정리합니다.

리눅스메모리운영체제OOM

리눅스에서 메모리 할당이 성공했다고 해서, 나중에 그 메모리를 실제로 쓸 때도 문제가 없다는 보장이 기본으로 주어지지는 않습니다. 할당 요청을 얼마나 엄격하게 따질지는 vm.overcommit_memory 설정이 정합니다. 이 글은 커널 문서 세 편, Overcommit Accounting, /proc/sys/vm 문서, /proc 파일 시스템 문서를 기준으로 세 모드의 차이와 /proc/meminfo의 CommitLimit, Committed_AS를 읽는 법을 정리합니다.

세 가지 모드

현재 값은 다음 명령으로 확인할 수 있습니다.

cat /proc/sys/vm/overcommit_memory
값 문서의 이름 동작
0 (기본값) 휴리스틱 오버커밋 요청 크기를 전체 메모리와 스와프의 합과 비교해 명백한 오버커밋만 거절합니다. 터무니없이 큰 할당은 실패시키고, 그 밖의 오버커밋은 허용해 스와프 사용을 줄입니다.
1 항상 오버커밋 실제로 메모리가 바닥날 때까지 메모리가 늘 충분한 것처럼 동작합니다.
2 오버커밋하지 않음 시스템 전체의 커밋 총량이 스와프와 물리 RAM의 일정 비율(기본 50%)을 더한 값을 넘지 못하게 합니다.

문서는 모드 1이 어울리는 예로 일부 과학 계산 코드를 듭니다. 희소 배열을 쓰면서 가상 메모리가 거의 전부 0 페이지로 남는다는 점에 기대는 코드입니다. 모드 2는 모든 페이지를 미리 초기화하지 않고도 할당받은 메모리를 나중에 쓸 수 있다고 보장받고 싶은 애플리케이션에 유용하다고 설명합니다. 오버커밋 자체가 쓸모 있는 이유로 /proc/sys/vm 문서는 “만일을 위해” 큰 메모리를 malloc()해 두고 대부분을 쓰지 않는 프로그램이 많다는 점을 듭니다.

모드 0이 무엇을 “명백한” 오버커밋으로 보는지 같은 세부는 문서에 적혀 있지 않습니다. /proc/sys/vm 문서는 더 자세한 내용으로 커널 소스 mm/util.c의 __vm_enough_memory()를 가리키는데, 이 글은 그 소스까지는 다루지 않습니다.

CommitLimit: 모드 2에서 지켜지는 상한

/proc/meminfo의 CommitLimit는 현재의 커밋 상한이고, Committed_AS는 지금까지 커밋된 양입니다. /proc 문서에 적힌 CommitLimit 공식은 다음과 같습니다.

CommitLimit = ([전체 RAM 페이지] − [전체 huge TLB 페이지]) × overcommit_ratio / 100 + [전체 스와프 페이지]

문서의 예로, 물리 RAM이 1G, 스와프가 7G이고 vm.overcommit_ratio가 30이면 CommitLimit는 7.3G입니다. 1G의 30%인 0.3G에 스와프 7G를 더한 값입니다.

비율 대신 절대량으로 정하려면 vm.overcommit_kbytes를 씁니다. 이때 커밋 총량은 스와프에 이 값만큼의 물리 RAM을 더한 양을 넘을 수 없습니다. 두 설정은 동시에 쓸 수 없어서, 하나를 설정하면 다른 하나는 꺼지고 읽으면 0으로 나옵니다.

여기서 놓치기 쉬운 점이 있습니다. CommitLimit 값은 /proc/meminfo에 늘 표시되지만, 이 상한을 실제로 지키는 것은 모드 2뿐입니다. overcommit_ratio와 overcommit_kbytes도 모드 2에서만 효과가 있습니다. 그래서 모드 0이나 1인 시스템에서 Committed_AS가 CommitLimit보다 크게 나와도 그것만으로 설정이 잘못됐다고 볼 수는 없습니다. 이 마지막 문장은 “모드 2에서만 지켜진다”는 문서 설명에서 이 글이 이끌어 낸 해석입니다.

Committed_AS는 실제 사용량이 아니라 약속한 양

Committed_AS는 프로세스들이 할당받은 메모리의 합이고, 아직 실제로 쓰지 않은 부분까지 들어갑니다. /proc 문서의 예로, 1G를 malloc()하고 그중 300M만 건드린 프로세스는 1G로 집계됩니다. 그 1G는 할당한 애플리케이션이 언제든 쓸 수 있도록 VM이 “커밋”, 즉 약속한 메모리이기 때문입니다.

어떤 매핑이 얼마로 집계되는지는 Overcommit Accounting 문서의 규칙을 따릅니다.

매핑 집계되는 비용
파일 매핑, SHARED 또는 읽기 전용 0 (매핑의 저장소는 스와프가 아니라 파일)
파일 매핑, PRIVATE이면서 쓰기 가능 인스턴스마다 매핑 크기
익명 또는 /dev/zero 매핑, SHARED 매핑 크기
익명 또는 /dev/zero 매핑, PRIVATE이면서 읽기 전용 0 (쓸모는 거의 없음)
익명 또는 /dev/zero 매핑, PRIVATE이면서 쓰기 가능 인스턴스마다 매핑 크기

이 밖에 mmap으로 쓰기 가능한 사본이 된 페이지와 shmfs 메모리도 같은 풀에서 집계됩니다. 문서의 상태 목록에는 mmap 매핑, mprotect로 인한 변화, mremap으로 인한 크기 변화, brk, munmap을 집계한다고 적혀 있고, ptrace 페이지 집계는 아직 할 일로 남아 있습니다.

내 시스템의 값 확인하기

grep -E '^(MemTotal|SwapTotal|CommitLimit|Committed_AS|HugePages_Total):' /proc/meminfo
cat /proc/sys/vm/overcommit_ratio /proc/sys/vm/overcommit_kbytes

/proc 문서에 실린 예시 출력을 이 방법으로 대조해 보겠습니다. 예시 출력에는 다음 값이 있습니다.

MemTotal:       32858820 kB
SwapTotal:             0 kB
CommitLimit:    16429408 kB
Committed_AS:    7715148 kB
HugePages_Total:       0

예시에는 overcommit_ratio 값이 나와 있지 않으므로 기본값 50이라고 가정합니다. 스와프가 0이면 MemTotal의 절반은 16,429,410 kB이고, 실제 CommitLimit는 16,429,408 kB로 2 kB 차이가 납니다. 공식은 페이지 단위로 정의되어 있고 문서는 이 차이를 설명하지 않습니다. 그래서 MemTotal로 하는 계산은 근삿값을 확인하는 용도로만 쓰는 편이 안전합니다. 같은 예시에서 Committed_AS(약 7.7GB)는 CommitLimit(약 16.4GB) 아래에 있습니다.

HugePages_Total을 함께 본 이유는 공식에서 huge TLB 페이지를 빼기 때문입니다. 이 값이 0이 아니라면 그만큼을 고려해야 합니다. hugetlb 관련 항목의 자세한 뜻은 이 글이 참고한 문서 범위 밖입니다.

어디서 실패하는가

모드 2에서는 대부분의 경우 프로세스가 페이지에 접근하다가 종료되는 대신, 메모리를 할당하는 시점에 오류를 받는다고 문서는 설명합니다. 다만 “대부분의 경우”라는 단서가 붙어 있고, 문서의 주의 사항(Gotchas)에 두 가지가 적혀 있습니다.

  • C 언어의 스택 성장은 암묵적인 mremap입니다. 절대적인 보장이 필요하고 한계에 가깝게 운영한다면, 필요하다고 생각하는 최대 크기로 스택을 mmap해 두어야 합니다. 일반적인 스택 사용에서는 큰 문제가 되지 않습니다.
  • 모드 2에서는 MAP_NORESERVE 플래그가 무시됩니다.

모드 1은 실제로 메모리가 바닥날 때까지 실패를 미룹니다. 모드 0은 앞에서 본 휴리스틱으로 명백한 오버커밋이라고 판단하면 그보다 이른 할당 시점에 요청을 거절할 수 있습니다. 실제로 OOM이 일어났을 때 /proc/sys/vm의 다음 두 설정은 커널 패닉 여부와 종료할 태스크를 고르는 방식에 영향을 줍니다.

  • panic_on_oom: 기본값 0이면 커널이 문제를 일으키는 프로세스를 골라 종료합니다(OOM killer). 1이나 2로 두면 커널 패닉을 일으킵니다. 1일 때는 mempolicy나 cpuset으로 사용 노드가 제한된 프로세스가 그 노드의 메모리를 다 쓴 경우 패닉 대신 OOM killer가 동작할 수 있고, 2는 memory cgroup 안의 OOM에서도 시스템 전체를 패닉시킵니다.
  • oom_kill_allocating_task: 기본값 0이면 OOM killer가 전체 태스크 목록을 훑어 휴리스틱으로 종료할 태스크를 고릅니다. 0이 아니면 OOM을 일으킨 태스크를 바로 종료해 목록 탐색 비용을 피합니다. panic_on_oom이 설정되어 있으면 그쪽이 우선합니다.

모드 2로 바꾸기 전에 확인할 것

먼저 상한이 얼마가 되는지 계산해 보세요. 설명용 가상 예로, RAM 16GiB에 스와프가 없고 huge TLB 페이지도 없는 서버에서 overcommit_ratio가 기본값 50이면 CommitLimit는 약 8GiB입니다. 모드 2에서는 실제 사용량과 별개로 커밋 총량이 이 값을 넘는 할당이 거부됩니다. 비율이 50이고 huge TLB 페이지가 없다면, 스와프가 RAM의 절반보다 작을 때 상한이 RAM 크기보다 작아진다는 점도 공식에서 바로 나옵니다.

그다음 예약분 두 가지를 봅니다.

  • user_reserve_kbytes: 모드 2에서 현재 프로세스 크기의 3%와 이 값 가운데 작은 쪽만큼 여유 메모리를 남겨 둡니다. 사용자가 메모리를 독차지하는 프로세스 하나를 띄워 놓고 그 프로세스를 종료할 수도 없게 되는 상황을 막기 위한 값입니다. 기본값은 min(현재 프로세스 크기의 3%, 128MB)이고, 모드 0과 1에서는 효과가 없습니다. 0으로 줄이면 프로세스 하나가 admin_reserve_kbytes를 뺀 모든 여유 메모리를 할당할 수 있고, 그 뒤 명령을 실행하려 하면 “fork: Cannot allocate memory”가 납니다.
  • admin_reserve_kbytes: cap_sys_admin 권한을 가진 사용자를 위해 남겨 두는 여유 메모리입니다. 기본값은 min(여유 페이지의 3%, 8MB)으로, 기본 휴리스틱 모드에서 관리자가 로그인해 프로세스를 종료할 정도를 의도한 값입니다. 문서는 모드 2 시스템에서는 복구에 쓸 프로그램들의 가상 메모리 크기 전체를 고려해 이 값을 늘려야 하며, 그렇지 않으면 root가 로그인하지 못할 수 있다고 경고합니다. 문서가 든 x86_64 기준 추정치는 sshd나 login, 셸, top 같은 도구를 합쳐 휴리스틱 모드에서 약 8MB, 모드 2에서 약 128MB입니다.

두 값 모두 바꾸면 애플리케이션이 메모리를 요청할 때부터 적용됩니다. /proc 문서는 커널 파라미터를 운영 시스템에서 바로 바꾸지 말고 개발 머신에서 먼저 시험해 보라고 권합니다.

누가 종료될지: oom_score_adj

OOM killer가 어느 프로세스를 고를지는 프로세스별 /proc/<pid>/oom_score_adj로 조정할 수 있습니다. 허용 범위는 -1000부터 +1000이고, 이 값이 badness 점수에 더해진 뒤 종료 대상을 정합니다. -1000은 해당 태스크의 OOM 종료를 사실상 끄는 값입니다. /proc/<pid>/oom_score는 현재 점수를 보여 주며, oom_score_adj가 반영되어 있어 사실상 0부터 2000 사이의 값입니다. 마지막으로 CAP_SYS_RESOURCE 프로세스가 설정한 값보다 낮추려면 CAP_SYS_RESOURCE가 필요합니다.

이 글의 범위와 한계

  • 이 글은 2026-10-12에 확인한 docs.kernel.org 문서(7.3.0-rc6 빌드)를 기준으로 합니다. /proc/sys/vm 문서 머리말에는 “Linux 2.6.29에 유효하다”는 오래된 문구가 남아 있지만, 이 글은 같은 빌드에 실린 현재 내용을 따랐습니다. 오래된 커널에서는 항목이나 기본값이 다를 수 있습니다.
  • 문서에 적힌 기본값은 커널 기본값입니다. 실제 시스템의 값은 위 명령으로 직접 확인하세요.
  • 모드 0의 세부 판정 로직(__vm_enough_memory())과 cgroup 메모리 제한에 걸려 생기는 OOM은 다루지 않았습니다. 후자에 대해 /proc 문서는 OOM이 메모리 제한 때문에 일어난 경우 badness 계산의 기준이 되는 “허용 메모리”가 그 제한값이 된다고만 설명합니다.
  • 커널 문서는 일반 서버에 어느 모드를 쓰라고 권하지 않습니다. 모드별 용도를 설명할 뿐이고, 이 글도 권장 모드를 제시하지 않습니다.

CommitLimit는 약속할 수 있는 총량의 상한이고, MemAvailable은 스와프 없이 새 프로그램에 내줄 수 있는 메모리의 추정치입니다. 둘은 서로 다른 질문에 답합니다. MemAvailable을 읽는 법은 free 명령의 available 글에서 다뤘습니다.

블로그로