/proc/meminfo, zoneinfo, smaps에는 모두 memory 수치가 나오지만, 같은 대상을 다른 이름으로 보여 주는 파일은 아닙니다. 시스템 전체 여유를 알고 싶은지, 특정 node의 allocation 제약을 보고 싶은지, process의 어느 mapping이 커졌는지에 따라 출발점이 달라집니다.
Linux v6.12의 문서와 구현을 기준으로, system·node·zone·process·page의 범위를 구분해 보겠습니다. 일부 파일은 kernel configuration과 권한에 따라 없거나 정보가 제한될 수 있습니다.
관찰과 memory 조작은 별개의 인터페이스입니다
Application의 allocation에는 libc의 malloc()과 그 내부 cache, kernel의 brk()·mmap() 경로가 관여합니다. munmap()은 mapping 제거, msync()는 file mapping의 동기화와 연결됩니다. 이러한 요청 API와 /proc에서 현재 상태를 조회하는 일은 구분해야 합니다.
brk()는 program break를 변경하는 syscall과 libc wrapper의 반환 규약을 구분해서 읽어야 합니다. sbrk()는 libc가 제공하는 관련 인터페이스이지 별도의 sbrk syscall이 아닙니다. 모든 libc allocator가 모든 요청에서 이 경로를 사용한다는 뜻도 아닙니다. Kernel의 allocation 경로를 관찰할 때는 allocator가 userspace에서 유지하는 free list와 cache도 고려해야 합니다.
Memory 범위를 다루는 API에도 목적별 차이가 있습니다. madvise()는 특정 동작에 대한 hint와 요청을, mprotect()는 접근 권한 변경을, mremap()은 mapping 변경을 다룹니다. mlock()·munlock()은 resident memory의 회수와 locking 정책에 연결됩니다.
접근을 추적하려면 soft-dirty, idle page tracking이나 DAMON처럼 서로 다른 관찰 수단이 있습니다. mincore()의 resident 정보는 이후 접근이 아무 fault 없이 끝난다는 보증이 아닙니다. userfaultfd는 지정한 종류의 fault 처리를 userspace와 연결하는 인터페이스입니다.
다른 process와 memory를 주고받거나 디버깅할 때는 process_vm_readv()·process_vm_writev(), ptrace() 및 권한을 갖춘 raw memory 접근 등의 경로를 구분해야 합니다. 단순한 통계 조회와 달리 data 접근 권한, 대상 process의 수명과 동기화가 직접적인 문제가 됩니다. Memory 공유도 mapping에 더해 data의 접근 순서를 정하는 IPC 규약이 필요합니다.
OOM 때 남는 kernel report와 SysRq의 memory dump도 관찰 수단입니다. 허용된 관리 환경에서 /proc/sysrq-trigger에 m을 쓰면 memory 정보가 kernel log에 출력될 수 있습니다. 이는 읽기 전용 통계 조회가 아니며 관리 권한과 kernel의 SysRq 지원을 확인해야 합니다. Keyboard용 /proc/sys/kernel/sysrq bitmask와 관리자 trigger 경로는 다릅니다. 정상 운영 환경에서 보고서를 얻기 위해 의도적으로 OOM을 유발할 필요는 없습니다. Linux v6.12 SysRq 문서
전체 사용량과 pressure는 다른 질문입니다
/proc/meminfo는 전체 RAM과 free memory, MemAvailable, cache, slab, swap과 commit 관련 수치를 읽는 출발점입니다. 주로 KiB 단위의 크기를 제공하지만, 모든 항목이 같은 단위이거나 서로 배타적인 것은 아닙니다. Huge page 개수처럼 단위가 다른 항목과, 다른 항목의 부분집합인 통계도 있습니다.
/proc/vmstat은 더 많은 VM counter를 노출합니다. 현재 상태를 나타내는 counter와 누적 event counter가 섞여 있으므로, 모든 줄을 현재 page 개수로 읽어서는 안 됩니다. 두 시점의 차이를 볼 때도 해당 항목이 누적값인지, 재시작이나 counter 갱신의 영향이 있는지 확인해야 합니다. 관련 출력은 vmstat_show()에서 따라갈 수 있습니다.
/proc/pressure/memory의 PSI는 memory가 얼마나 남았는지보다, memory 부족 때문에 실행이 얼마나 지연되는지에 관한 관찰입니다. some과 full, 평균 구간과 total을 구분해서 읽어야 합니다. 높은 memory 사용량과 높은 memory pressure가 항상 같은 상황은 아닙니다.
Node와 zone의 제약으로 내려갑니다
/proc/zoneinfo에는 node별 통계와 zone별 watermark, reserve, page 수와 PCP 관련 정보가 나옵니다. Node 통계가 zone마다 독립적인 값처럼 반복되는 것인지 먼저 확인하고, 여러 zone의 출력을 무작정 합하지 않아야 합니다.
Zone의 spanned, present, managed는 각각 범위, 존재하는 memory와 allocator 관리 범위를 구별합니다. free는 그중 현재 여유를 나타내는 별도 값입니다. protection은 다른 zone에서 fallback하는 요청을 위해 적용하는 lowmem reserve를 해석할 때 필요합니다.
CPU별 pageset에는 count, high, batch 등 PCP의 상태와 조정 정보가 나옵니다. count는 그 cache 안의 base pages이며, 높은 order block은 포함된 base pages 수로 계산합니다. high와 batch는 cache를 유지하거나 buddy 쪽과 주고받는 정책을 이해하는 단서입니다. 최신 구현에서 동적으로 조정하는 값까지 오래된 고정 공식으로 일반화해서는 안 됩니다.
vm stats threshold는 통계 갱신을 묶는 기준과 관련되며 PCP의 free memory 그 자체와는 다릅니다. CPU별 통계를 즉시 global에 합치는 비용을 줄이므로, 빠른 통계가 언제나 정밀한 순간 snapshot은 아니라는 점도 연결됩니다.
Buddy와 pageblock의 분포를 구분합니다
/proc/buddyinfo는 node·zone별 free block을 order별로 보여 줍니다. Base page가 4 KiB라면 order 4의 block 3개는 3 * 16 * 4 KiB입니다. 표의 3을 단순히 3 pages로 읽으면 안 됩니다. 이 표는 buddy free list의 분포이므로 PCP와 같은 범위도 아닙니다.
/proc/pagetypeinfo는 migrate type별 free block과 pageblock의 배정을 더 자세히 보여 줍니다. Free list 표와 pageblock 개수 표는 서로 다릅니다. 후자는 allocation된 부분을 포함한 pageblock의 분류를 이해하는 정보이며, 전부 지금 할당할 수 있는 free memory라는 뜻이 아닙니다.
Pageblock order가 9이고 base page가 4 KiB인 예라면 한 pageblock은 512 pages, 즉 2 MiB입니다. 이 값은 해당 환경의 예이지 모든 architecture의 고정값은 아닙니다. CONFIG_PAGE_OWNER 등 configuration에 따라 추가 정보가 나올 수도 있습니다.
Kernel allocation을 좁혀 봅니다
/proc/slabinfo는 slab cache별 object와 slab 관련 정보를 제공합니다. Active object 수, total object 수, object 크기와 slab page 비용은 다른 값입니다. Object 개수에 object 크기를 곱한 값만으로 allocator의 모든 memory 비용이 계산되는 것은 아닙니다.
/proc/vmallocinfo에서는 kernel virtual allocation 범위와 크기, 가능한 경우 caller 등의 정보를 살펴볼 수 있습니다. Pointer 출력은 권한과 kernel의 주소 노출 정책에 의해 제한될 수 있습니다. 분석 편의를 위해 주소 보호를 무조건 해제하는 것을 일반적인 절차로 삼으시면 안 됩니다.
/proc/kcore는 ELF core 형식으로 kernel address space의 일부를 조사하는 고급 진단 인터페이스입니다. File에 보이는 크기를 실제 RAM 사용량으로 읽거나, 일반적인 disk file처럼 전체를 복사해서 분석하는 방식은 적합하지 않습니다. Live kernel을 다루는 도구와 적절한 symbol 및 권한이 필요한 영역입니다.
Process에서는 mapping과 resident 통계를 나눕니다
/proc/PID/maps는 VMA의 주소 범위, 접근 권한과 private/shared 구분, file offset, device·inode와 경로 등을 보여 줍니다. [heap], [stack], [vdso], [vsyscall]과 이름 붙은 anonymous mapping도 구분해서 읽습니다. 모든 thread의 stack이 언제나 같은 이름으로 나타나는 것은 아닙니다.
maps의 r, w, x는 접근 권한을, p와 s는 private/shared mapping을 뜻합니다. 경로가 file을 가리킨다는 사실만으로 범위의 모든 resident page가 아직 file page라는 뜻은 아닙니다. Private file mapping 중 일부는 CoW로 anonymous page가 되었을 수 있습니다.
Linux v6.12의 show_vma_header_prefix()가 p/s를 고르는 bit는 VM_MAYSHARE입니다. VmFlags의 sh가 대응하는 VM_SHARED와 무조건 같은 bit라고 설명하면 안 됩니다. File offset은 byte 단위이며 file-backed VMA의 vm_pgoff에 PAGE_SHIFT를 적용해 출력합니다. 주소 범위는 시작을 포함하고 끝을 포함하지 않습니다.
이름도 allocator 종류의 완전한 목록은 아닙니다. [heap]은 초기 brk 범위와 겹치는 VMA, [stack]은 초기 stack 위치를 포함하는 VMA를 식별하는 helper와 연결됩니다. 모든 malloc() 결과가 [heap] 안에 있거나 모든 thread stack에 [stack]이 붙는 것은 아닙니다. 이름을 지정한 anonymous mapping은 [anon:이름], shared anonymous mapping은 [anon_shmem:이름]으로 표시될 수 있습니다. vDSO·vvar·legacy vsyscall 표시는 architecture와 설정에 따라 다르며, get_vma_name()은 file·VMA operation·architecture별 이름 등을 순서대로 확인합니다. 그 구현의 vm_mm == NULL fallback에 [vdso]가 있다는 사실을 모든 kernel mapping의 보편적 분류 규칙으로 넓히지는 않습니다.
smaps는 이 VMA별 기본 정보에 resident, proportional, dirty, referenced, anonymous와 swap 통계를 더합니다. Size와 Rss는 각각 virtual 범위와 resident memory라는 다른 양입니다. Referenced도 모든 byte에 대한 최근 접근의 완벽한 기록이 아니라 page 및 PTE의 관찰 상태에 기반합니다.
Anonymous는 MAP_PRIVATE 여부 자체가 아니라 실제 backing page의 anonymous 성격을 조사합니다. File page를 읽은 것만으로 CoW가 생기는 것은 아니며, private write 후 만들어진 anonymous copy와 구분합니다. 보통의 anonymous read fault가 shared zero page로 처리된 경우에는 일반적인 private resident page 한 개를 할당한 것처럼 RSS를 늘리지 않습니다. Zero page와 특수 mapping의 집계는 smaps의 ordinary page 경로와 분리해서 읽어야 합니다.
LazyFree는 MADV_FREE와 연결됩니다. 해제를 허용했지만 아직 회수되지 않은 anonymous memory가 관찰될 수 있고, 다시 쓰면 회수에 관한 취급이 달라질 수 있습니다. VmFlags에는 VMA flag의 mnemonic이 나오며, rd/wr/ex와 mr/mw/me처럼 현재 permission과 허용 가능한 permission을 구분해야 합니다.
smaps의 Locked는 locking된 부분의 proportional 집계와 연결됩니다. 이를 status의 VmLck나 단순한 VMA 길이와 동일한 수치로 가정하면 안 됩니다. 공유 정도와 실제 page 상태가 집계에 영향을 줍니다.
smaps_rollup은 개별 VMA별 출력 대신 process 합계를 제공합니다. 여기의 Pss_Anon, Pss_File, Pss_Shmem은 backing 분류를 이해하는 항목입니다. MAP_PRIVATE라는 flag 하나로 범위 전체를 anonymous 통계로 분류할 수는 없습니다. 아직 CoW하지 않은 file pages와 이미 anonymous copy가 된 pages를 구별해야 합니다.
status에서 VmSize와 VmPeak는 virtual size의 현재값과 peak를, VmLck와 VmPin은 locking과 pinning에 관한 별도 통계를 보여 줍니다. 이 항목들이 RSS와 같은 양을 서로 다른 이름으로 표시하는 것은 아닙니다. smaps_rollup의 합계에도 개별 VMA의 KernelPageSize, MMUPageSize, THPeligible, ProtectionKey처럼 단순히 더해서 process 전체의 단일 값으로 만들지 않는 정보가 있습니다.
경로를 찾는 인터페이스와 data를 읽는 인터페이스
/proc/PID/map_files의 start-end 항목은 mapping과 file의 연결을 찾는 symlink입니다. /proc/PID/numa_maps에서는 mapping별 NUMA policy와 node별 page 분포 등의 정보를 확인할 수 있습니다. 단순히 file 이름이 비슷하다는 이유로 모든 파일이 동일한 page-table walk를 수행한다고 가정해서는 안 됩니다.
numa_maps의 N0=12는 node 0에 해당하는 12 pages라는 뜻입니다. mapmax는 해당 범위에서 관찰한 최대 mapping count이며, 범위 전체를 공유하는 process의 정확한 개수로 읽지 않습니다. File 이름은 복수형인 numa_maps입니다. map_files의 entry 역시 이름이 directory처럼 보인다고 하위 directory 자체를 나열한 것은 아닙니다.
/proc/PID/pagemap은 virtual page별 상태를, /proc/kpagecount와 /proc/kpageflags는 PFN별 정보를 제공합니다. 뒤의 두 파일은 /proc/PID/ 아래에 있지 않습니다. Pagemap의 virtual index와 global 파일의 physical index를 혼동하지 않는 것이 중요합니다.
/proc/PID/mem은 해당 process의 virtual address를 offset으로 사용하는 raw memory 접근 인터페이스입니다. 단순한 memory 통계 파일이 아니며 tracing 관련 권한 검사가 적용됩니다. 다른 process의 memory를 읽거나 쓰는 기능은 GUP 및 원격 접근 경로와 이어지므로, 진단 과정에서 아무 권한으로나 사용할 수 있다고 가정하시면 안 됩니다.
OOM과 관련해서는 /proc/PID/oom_score와 oom_score_adj가 있습니다. 전자는 선택에 관련된 점수, 후자는 사용자가 조정하는 값이며 RSS와 같은 byte 수가 아닙니다. Deprecated된 oom_adj와도 구분해야 합니다.
oom_score_adj의 범위는 -1,000부터 1,000까지이며, -1,000은 해당 OOM victim 선택에서의 보호에 특별한 의미가 있습니다. 모든 memory 제한을 무시하고 무제한 allocation을 허용하는 값은 아닙니다.
처음부터 모든 파일을 모으기보다 조사하려는 범위를 먼저 정하시면 출력이 훨씬 읽기 쉬워집니다. System 총량에서 allocation 제약으로, process 합계에서 VMA와 page로 내려가는 식으로 질문을 좁혀 가시면 됩니다.
참고 자료
- Lorenzo Stoakes, The Linux Memory Manager, Early Access edition, 2025, §14.5.1–14.5.2 및 각 인터페이스 개요.
- Linux v6.12
/procdocumentation - Linux v6.12
mm/vmstat.c - Linux v6.12 PSI documentation