vm.swappiness를 낮추면 memory가 더 생길까요? min_free_kbytes를 늘리면 allocation 실패가 사라질까요? Tunable은 memory를 추가하는 장치가 아니라 kernel이 어떤 비용과 제약을 우선할지 바꾸는 입력입니다.
여기서는 Linux v6.12의 /proc/sys/vm/ 문서와 구현을 기준으로 각 설정이 관여하는 범위를 살펴보겠습니다. 기본값은 배포판과 kernel configuration에서 달라질 수 있습니다. 아래에서는 설정을 일괄 변경하지 않고 의미를 구분하는 데 집중하겠습니다.
먼저 commit과 resident memory를 나눕니다
overcommit_memory는 주소 공간을 요청할 때 memory commitment를 판단하는 방식에 관여합니다. Mode 0은 heuristic, 1은 overcommit을 허용하는 쪽, 2는 commit limit을 엄격히 적용하는 쪽입니다. Mode 1이라고 해서 주소, 권한, resource limit, metadata allocation 등의 모든 검사가 사라지는 것은 아닙니다.
Mode 2에서 limit은 swap과 RAM의 일부를 바탕으로 계산됩니다. 비율 설정은 overcommit_ratio, 고정 크기 설정은 overcommit_kbytes입니다. 후자의 단위는 이름 그대로 KiB이며 overcommit_bytes라는 이름으로 바꾸어 사용하시면 안 됩니다. HugeTLB 등 계산상 제외 항목과 관련 reserve도 있어, 단순히 설치 RAM 전체에 비율을 곱하는 것만으로 설명이 끝나지는 않습니다.
/proc/meminfo의 CommitLimit과 Committed_AS를 관찰할 수 있습니다. 이 수치들은 현재 RSS나 MemAvailable과 다른 것입니다. Commit을 승인했더라도 모든 page가 이미 RAM에 resident한 것은 아니며, 반대로 resident data만 더한 값으로 future commitment를 대신할 수는 없습니다.
admin_reserve_kbytes와 user_reserve_kbytes는 복구를 위한 여유와 특정 사용자의 과도한 commitment에 관련된 보호를 이해할 때 함께 볼 항목입니다. 문서의 초기값 기준으로 admin reserve는 free pages의 약 3%와 8 MiB 중 작은 값, user reserve는 약 3%와 128 MiB 중 작은 값입니다. 이 기본값이 자신의 복구 도구를 실행하기에 충분한지는 별개의 문제이며, overcommit mode별 실제 적용 경로도 구분해야 합니다.
Linux v6.12의 init_admin_reserve()와 init_user_reserve()가 실제로 사용하는 비율은 초기 free KiB의 정수 나눗셈 1/32입니다. 8 MiB와 128 MiB는 이 초기 계산의 상한이지 sysctl에 더 큰 값을 설정하지 못하게 하는 영구 한도가 아닙니다. 같은 version의 __vm_enough_memory()에서 mode 2는 관리자 capability가 없으면 admin reserve를 허용량에서 뺍니다. mm이 있으면 추가로 min(mm->total_vm / 32, user reserve의 page 환산값)을 뺍니다. User reserve를 해당 UID의 모든 process에 대한 합산 한도라고 읽으면 이 계산과 달라집니다.
Mapping 개수와 낮은 주소의 보호는 별도입니다
max_map_count는 process의 VMA 개수를 제한합니다. Mapping 길이를 모두 더한 byte 수의 한도가 아닙니다. VMA split과 merge에 따라 같은 총 주소 범위라도 개수가 달라질 수 있습니다. 기본값이나 core dump 형식에 관한 역사적 설명만으로 현재 한도를 결정하지 말고, 실제 값과 workload의 VMA 수를 함께 확인해야 합니다.
Linux v6.12의 기본 정의는 USHRT_MAX - 5, 즉 65535 - 5 = 65530입니다. 65536 - 5가 아닙니다. Header에는 ELF core dump의 16-bit 개수와 여유분에 관한 역사적 설명 및 extended numbering에 관한 단서가 함께 있습니다. 이를 현재 ELF가 65,535개를 넘는 mapping을 절대로 표현할 수 없다는 법칙으로 사용하지 않습니다. Linux v6.12 include/linux/mm.h
mmap_min_addr는 낮은 virtual address의 mapping을 제한하는 보안 관련 입력입니다. LSM과 capability 등의 검사도 함께 관여할 수 있습니다. Pointer 값 0을 특별하게 다룬다는 C의 규칙과 kernel이 낮은 주소를 허용하는지는 다른 층의 문제입니다. 문제를 피하려고 이 보호를 무조건 낮추는 방식은 적합하지 않습니다.
Zone reserve와 watermark를 혼동하지 않습니다
min_free_kbytes는 zone의 최소 watermark 계산에 영향을 줍니다. 값을 크게 한다고 free memory가 실제로 추가되는 것은 아닙니다. 일반 allocation에 사용할 수 있는 여유를 줄이거나 reclaim을 더 일찍 유도하는 쪽의 효과도 함께 생길 수 있습니다.
calculate_min_free_kbytes()의 초기 계산에는 int_sqrt(lowmem_kbytes * 16), 즉 대략 4 * sqrt(lowmem_kbytes)가 쓰입니다. 여기의 입력은 nr_free_buffer_pages()를 KiB로 환산한 값이지 현재 RSS나 설치 RAM 전체가 아닙니다. Linux v6.12의 이 계산은 128-262,144 KiB 범위의 clamp와 기존 사용자 지정값의 우선 조건을 갖고, 이후 THP 관련 조정도 있으므로 하나의 식만으로 최종 실행값을 단정하지 않습니다.
lowmem_reserve_ratio는 상위 zone 요청이 낮은 zone으로 fallback할 때 보호할 양을 계산하는 데 사용합니다. 분모 형태의 입력이라는 점이 중요합니다. 숫자가 커지면 보호량도 언제나 커질 것이라는 직관은 맞지 않을 수 있습니다. Node의 zone 크기와 fallback 방향을 함께 보아야 합니다.
Linux v6.12의 setup_per_zone_lowmem_reserve()는 해당 node의 더 높은 zone들에 있는 managed pages를 누적한 뒤 낮은 zone의 ratio로 나눕니다. 예를 들어 관련 상위 zone 합계가 262,144 pages라면 ratio 256에서 reserve는 1,024 pages, ratio 128에서는 2,048 pages입니다. 4 KiB base page 기준 각각 4 MiB와 8 MiB입니다. 실제 구현에는 비어 있는 zone과 ratio 0 등의 별도 처리가 있습니다.
watermark_scale_factor는 watermark 간격을 조정하며 10,000분의 1 단위로 해석하는 입력입니다. watermark_boost_factor는 fragmentation과 관련된 watermark boost에 관여합니다. 두 설정을 같은 비율의 같은 동작으로 보시면 안 됩니다. 기본값과 계산에 쓰는 zone 범위는 해당 version의 구현과 실제 시스템 값으로 확인해야 합니다.
Linux v6.12 문서의 scale 기본값 10은 managed memory의 0.1%에 해당하는 간격 계산과 연결되며, 허용 최대값 3,000은 30%에 해당합니다. Boost 기본값 15,000은 high watermark의 150%를 기준으로 한 boost 상한 계산에 쓰입니다. 설정하자마자 항상 그 양의 boost가 즉시 적용된다는 의미는 아닙니다.
높은 watermark를 유지하면 background reclaim이 더 적극적으로 동작하거나 allocation을 위해 남기는 양이 달라질 수 있습니다. 반면 실제로 회수할 수 없는 workload에서 숫자만 바꾸면 성능 비용만 커질 수도 있습니다. 실패한 allocation의 node·zone·order·GFP 조건을 먼저 파악해야 합니다.
Compaction을 전부 끄는 설정과 proactive 동작을 구분합니다
compact_memory는 write에 의해 compaction을 요청하는 trigger입니다. compaction_proactiveness는 background에서 얼마나 적극적으로 미리 compaction을 수행할지에 관여합니다. 값을 0으로 했다고 모든 direct compaction까지 사라지는 것은 아닙니다.
compact_unevictable_allowed는 unevictable memory에 관한 compaction 동작을 조정합니다. Reclaim에서 빼 두었다는 사실과 physical 위치를 이동할 수 있는지는 같은 질문이 아닙니다. Realtime configuration에서는 지연 비용에 관한 고려도 달라질 수 있습니다.
Compaction은 흩어진 free memory를 연속된 범위로 만들기 위한 작업과 연결됩니다. 총 사용량을 줄이는 reclaim과 목적이 다르므로, available memory가 적은 문제와 높은 order의 fragmentation 문제를 구분해서 평가해야 합니다. 더 적극적인 compaction에는 CPU 사용량과 latency 비용이 생길 수 있습니다.
Swap과 file cache의 비용을 비교합니다
swappiness는 reclaim에서 swap-backed memory와 file-backed memory의 상대적인 비용 판단에 관여합니다. Linux v6.12 문서는 0~200 범위를 설명합니다. 100은 상대 비용을 같게 보는 출발점이며, 빠른 in-memory swap 등을 사용하는 환경에서는 높은 값이 의미를 가질 수도 있습니다.
Upstream의 기본값 60은 비교의 출발점일 뿐 자신의 장치에서 최적인 측정 결과가 아닙니다. 이 값은 swap을 몇 % 채우라는 목표치나 RSS 대비 swap 비율도 아닙니다.
0을 swap 기능 전체의 금지 스위치로 이해하면 안 됩니다. 사용 가능한 swap이 남아 있어도 어떤 조건과 압력에서 무엇을 먼저 회수할지는 reclaim 구현과 정책에 따라 달라집니다. 느린 swap 장치의 비용과 반복되는 file-cache refault 비용을 실제 workload에서 비교해야 합니다.
page-cluster는 swap readahead에서 한 번에 살펴볼 pages의 범위에 관한 입력이며, page 개수 자체가 아니라 지수 형태로 해석됩니다. 다만 모든 swap fault가 항상 그 수만큼 I/O를 수행하는 것은 아닙니다. VMA 기반 readahead 등 실제 활성 경로도 확인해야 합니다.
예를 들어 값 3은 2^3 = 8 pages에 대응하는 최대 cluster 범위의 출발점이며, 값 0은 한 page에 대응합니다. Upstream의 일반 초기값은 3이지만 작은 memory 환경의 초기화 조건과 실제 sysctl을 별도로 확인합니다.
zone_reclaim_mode는 NUMA 시스템에서 원격 node로 가기 전에 local reclaim을 시도하는 정책과 연결됩니다. Reclaim, write, unmap에 관한 bit를 조합할 수 있지만, 조합을 늘릴수록 항상 좋은 것은 아닙니다. Locality와 I/O·unmap 지연의 trade-off를 이해해야 합니다.
Linux v6.12의 관련 내부 bit 이름은 RECLAIM_ZONE(값 1), RECLAIM_WRITE(값 2), RECLAIM_UNMAP(값 4)입니다. 값 1은 local reclaim을 켜는 쪽, 나머지는 그 과정에서 writeback이나 unmap을 허용하는 선택과 연결됩니다. 기본 enable 조건과 부가 동작의 허용을 같은 bit로 보시면 안 됩니다.
OOM 정책은 실패를 숨기는 용도가 아닙니다
oom_dump_tasks는 OOM 시 task 정보를 출력하는 데 관여합니다. oom_kill_allocating_task는 조건에 맞는 triggering task를 우선 대상으로 삼는 정책입니다. Triggering task가 가장 큰 점유자라는 보장은 없으므로, log 첫 줄만으로 이 설정이 더 공정하다고 판단하시면 안 됩니다.
panic_on_oom은 OOM에서 kernel panic을 선택하는 정책에 관여합니다. Linux v6.12의 check_panic_on_oom()에서 0은 이 sysctl에 의한 강제 panic을 선택하지 않고, 1은 CONSTRAINT_NONE인 OOM에 적용됩니다. Cpuset, mempolicy나 memcg에 의해 제한된 OOM에서는 값 1의 이 panic 경로를 생략합니다. 값 2는 그런 제한이 있는 경우에도 강제 panic을 적용하는 쪽입니다.
SysRq로 유도한 OOM에는 이 helper의 별도 예외가 있습니다. 또한 값 0이 모든 원인의 kernel panic을 금지하는 것은 아닙니다. 숫자를 올려 memory 부족을 해결하는 설정이 아니라 장애 대응 방식 자체를 바꾸는 정책이므로 운영 요구와 별도로 떼어서 결정해서는 안 됩니다.
Tunable을 평가할 때는 변경 전후의 값뿐 아니라 allocation 실패, reclaim·swap event와 PSI, latency를 같은 workload에서 비교해야 합니다. 서로 다른 문제에 관여하는 설정 여러 개를 동시에 바꾸면 어떤 변화가 효과나 부작용을 만들었는지 알기 어렵습니다.
참고 자료
- Lorenzo Stoakes, The Linux Memory Manager, Early Access edition, 2025, §14.6.
- Linux v6.12 VM sysctl documentation
- Linux v6.12 overcommit documentation
- Linux v6.12
mm/page_alloc.c - Linux v6.12
mm/util.c