Linux 메모리 관리 기초
개요
Linux 메모리 관리는 프로세스마다 독립된 가상 주소 공간을 제공하고, 그 뒤에서 실제 물리 메모리와 파일을 연결하는 핵심 서브시스템입니다. mmap()으로 만든 매핑, malloc()이 쓰는 힙, 스택, 파일 매핑은 모두 커널의 페이지 폴트 처리와 페이지 테이블 갱신을 거치며 실제 페이지를 확보합니다.
파일을 읽고 쓰는 경로와 mmap()으로 파일을 다루는 경로는 대부분 page cache를 공유합니다. 반대로 익명 메모리(힙, 스택, MAP_ANONYMOUS)는 파일 대신 swap과 reclaim 정책에 더 직접적으로 묶입니다. 메모리가 부족해지면 커널은 reclaim과 kswapd를 통해 먼저 여유를 만들고, 그래도 실패하면 OOM 처리로 넘어갑니다.
그림 1. 사용자 공간, page cache, anonymous memory, reclaim, OOM의 연결 구조
핵심 개념
가상 메모리와 VMA
각 프로세스는 자신만의 가상 주소 공간을 보며, 커널은 이를 Virtual Memory Area(VMA) 단위로 관리합니다. VMA는 특정 주소 구간이 파일에 매핑되는지, 익명 메모리인지, 읽기 전용인지 같은 속성을 담고 있습니다.
mmap()은 파일이나 익명 메모리에 대한 새 매핑을 만듭니다.brk()기반 힙 확장도 결국 VMA 범위를 넓히는 동작입니다.- 주소 변환은 페이지 테이블과 MMU가 담당하고, 실제 페이지는 첫 접근 시점에 채워질 수 있습니다.
mmap()과 demand paging
mmap()은 파일이나 익명 객체를 가상 주소 공간에 연결합니다. 커널은 호출 시점에 모든 페이지를 다 채우지 않아도 되므로, 실제 메모리 할당은 첫 접근 때 page fault로 늦춰질 수 있습니다.
MAP_SHARED는 같은 매핑을 여러 프로세스가 공유하고, 변경 내용이 파일이나 shared object에 반영될 수 있습니다.MAP_PRIVATE는 COW(copy-on-write) 경로를 사용해 쓰기 시점에만 복사합니다.MAP_ANONYMOUS는 파일 backing 없이 zero-filled 페이지로 시작합니다.
page cache
page cache는 파일 시스템과 커널이 만나는 기본 캐시입니다. 커널 문서에 따르면 정상적인 read, write, mmap 접근은 모두 page cache를 통해 파일 데이터와 연결됩니다.
- 파일-backed page는 여러 프로세스가 같은 내용을 공유하기 쉽습니다.
- dirty page는 즉시 디스크로 쓰이지 않고, writeback 과정에서 반영됩니다.
mmap()으로 본 파일 페이지도 같은 cache를 재사용하므로 I/O 중복을 줄일 수 있습니다.
reclaim, swap, kswapd
메모리가 부족해지면 커널은 cold page를 회수해 새 할당을 위한 공간을 만듭니다. 이 과정은 직접 reclaim으로 호출 경로에서 수행되기도 하고, background thread인 kswapd가 대신 처리하기도 합니다.
- reclaim은 LRU 계열 목록에서 오래 안 쓴 페이지를 우선적으로 봅니다.
- anonymous page는 필요하면 swap으로 밀릴 수 있습니다.
- file-backed page는 더 재생성하기 쉬우면 우선 회수 대상이 됩니다.
zone, NUMA, huge page
기본적인 사용자 공간 메모리 흐름 아래에는 물리 메모리 배치와 할당 정책도 함께 존재합니다. Linux는 물리 메모리를 zone과 node 관점으로 나눠 관리하고, 큰 working set에서는 huge page 계열 정책이 TLB 효율과 reclaim 패턴에 영향을 줍니다.
- zone은 DMA 제약이나 직접 매핑 가능 범위 같은 하드웨어 특성에 따라 페이지를 분류합니다.
- NUMA 시스템에서는 node마다 메모리 거리가 다르므로, 같은 할당이라도 어느 node에서 확보했는지가 지연 시간과 대역폭에 영향을 줍니다.
- THP(Transparent Huge Pages)는 페이지 테이블 깊이와 TLB miss를 줄일 수 있지만, compaction이나 reclaim 비용과 함께 봐야 합니다.
OOM 처리
reclaim과 swap으로도 충분한 공간을 만들지 못하면 OOM(out of memory) 경로가 동작합니다. 이때 커널은 희생 프로세스를 골라 메모리를 회수해 시스템 전체를 살리려 합니다.
- OOM은 단순히 "메모리가 없다"는 알림이 아니라, 더 이상 안전하게 진행할 수 없을 때의 최후 수단입니다.
- 메모리 압박이 심한 워크로드에서는 OOM 이전에 reclaim 패턴을 먼저 보는 편이 좋습니다.
비교/분석
| 항목 | backing | 첫 접근 | 공유 특성 | 압박 시 특징 |
|---|---|---|---|---|
| Anonymous memory | 파일 없음, zero page 출발 | write 또는 fault 시 페이지 할당 | 기본적으로 private | swap 대상이 되기 쉽고 COW 비용이 있음 |
| File-backed memory | 파일과 page cache | fault 시 캐시 hit 또는 디스크 read | 같은 파일 페이지를 여러 프로세스가 재사용 | dirty page writeback이 필요함 |
| Shared memory | shared object 또는 MAP_SHARED |
fault 시 page cache 또는 tmpfs 페이지 확보 | 프로세스 간 내용이 보이도록 동기화 | 일관성 유지가 중요하고 reclaim 정책 영향이 큼 |
mmap() vs read/write |
둘 다 파일 I/O와 연결 | mmap()은 page fault, read/write는 syscall copy |
mmap()은 주소 공간에 직접 노출 |
큰 파일/반복 접근에서는 page cache 재사용이 유리 |
동작 원리
- 프로그램이
malloc(),brk(),mmap(),read()같은 경로로 메모리나 파일 데이터를 요청합니다. - 커널은 VMA와 페이지 테이블 항목을 준비하고, 실제 페이지는 필요한 시점에 fault로 채웁니다.
- 파일-backed 접근이면 page cache를 먼저 확인하고, 없으면 파일에서 읽어 들입니다.
- anonymous 접근이면 zero page 또는 새 페이지를 할당하고,
MAP_PRIVATE인 경우 쓰기 시 COW가 발생합니다. - 할당 시점에는 zone 제약, NUMA node, huge page 가능성 같은 물리 메모리 조건도 함께 고려됩니다.
- 메모리 압박이 커지면 reclaim과
kswapd가 cold page를 회수합니다. - 회수할 수 있는 공간이 부족하면 필요에 따라 compaction이 먼저 시도될 수 있고, 그래도 부족하면 OOM 처리로 넘어갑니다.
이 흐름 때문에 Linux 메모리 관리는 "할당"만이 아니라 "재사용"과 "회수"까지 함께 봐야 이해가 됩니다. /proc/meminfo, /proc/<pid>/maps, /proc/<pid>/smaps를 함께 보면 현재 메모리 상태와 매핑 구성을 파악하기 좋습니다.
장단점
- 장점: 가상 주소 공간과 실제 물리 메모리를 분리해 프로세스 격리와 유연한 할당을 제공합니다.
- 장점: page cache 재사용 덕분에 파일 I/O와
mmap()이 효율적으로 연결됩니다. - 장점: reclaim과 swap으로 메모리 압박을 흡수할 수 있습니다.
- 단점: page fault와 reclaim은 지연을 유발할 수 있습니다.
- 단점: 잘못된 메모리 사용 패턴은 thrashing과 OOM으로 이어질 수 있습니다.
- 단점: dirty page와 COW 페이지는 회수 비용이 더 큽니다.
- 단점: THP, compaction, NUMA locality 같은 요소까지 겹치면 성능 분석이 빠르게 복잡해집니다.
관련 기술
- Virtual Memory
- Memory Hierarchy
- Linux Memory Tiering Deep
- VFS FS PageCache BlockIO
- Linux kernel memory management
- Concepts overview
- Page Cache
- Multi-Gen LRU
- Transparent Hugepage Support
- Out Of Memory Handling
- mmap(2)
- proc(5)
핵심 정리
Linux 메모리 관리는 프로세스의 가상 주소 공간을 실제 메모리와 파일에 연결하고, 필요할 때만 페이지를 채우는 구조입니다. 파일-backed 접근은 page cache를 통해 재사용성이 높고, anonymous 메모리는 swap과 reclaim의 영향을 더 직접적으로 받습니다. 메모리 압박이 생기면 kswapd와 reclaim이 먼저 동작하고, 그럼에도 공간이 부족하면 OOM 처리로 이어집니다. 따라서 성능을 볼 때는 할당 속도뿐 아니라 page fault, writeback, reclaim, OOM까지 한 흐름으로 봐야 합니다.