Reddit

Page table memory consumption

페이지 테이블 메모리 사용량

페이지 테이블은 매핑한 데이터 크기의 약 1/512만큼 메모리를 쓰지만, 같은 메모리를 여러 주소 공간에 매핑하면 비용이 누적됩니다. 글은 데이터베이스와 NUMA 사례를 통해 페이지 테이블이 메모리 압박과 원격 메모리 지연의 원인이 되는 과정을 설명합니다.

AI 요약

페이지 테이블은 가상 주소를 물리 메모리로 연결하는 자료구조입니다. Linus Torvalds는 해시 방식보다 트리 구조가 TLB(Translation Lookaside Buffer) 채우기에 유리하다고 주장했습니다. 트리에서는 인접 페이지의 항목도 메모리에서 가까이 놓이므로 캐시 라인 하나를 읽을 때 TLB 항목 여러 개를 함께 채울 수 있습니다. 글은 보통의 Intel CPU가 한 번에 TLB 항목 8개를 가져오는 사례를 들어, 페이지 테이블 설계에서 메모리 접근 지연뿐 아니라 항목 배치도 중요하다고 설명합니다.

매핑이 늘면 페이지 테이블도 커집니다

4 KiB 데이터 페이지 하나를 매핑하는 PTE(Page Table Entry)는 8바이트입니다. 페이지를 한 주소 공간에서 한 번 매핑하면 페이지 테이블 메모리는 데이터 크기의 약 1/512입니다. 하지만 같은 물리 페이지를 여러 주소 공간에서 매핑하면 각 주소 공간마다 별도의 PTE가 필요합니다. 같은 페이지를 512개 주소 공간이 매핑하면 PTE 512개가 4 KiB를 차지합니다. 이 경우 페이지 테이블 비용만으로 데이터 페이지 하나만큼의 메모리를 씁니다.

글은 이런 비용이 오래전부터 실제 메모리 부족 문제를 일으켰다고 짚습니다. 2002년 Andrea Arcangeli는 64 GiB 메모리의 x86 시스템에서 수백 개 프로세스가 같은 1 GiB 공유 메모리를 매핑해도 메모리가 부족해지는 문제를 다뤘습니다. PAE를 쓴 32비트 x86에서는 페이지 테이블이 약 896 MiB 규모의 lowmem 영역에 놓였습니다. 수정안은 페이지 테이블을 highmem으로 옮겼습니다.

2022년 Khalid Aziz는 512 GB 메모리를 장착한 Oracle 서버에서 1,500개가 넘는 클라이언트가 300 GB SGA(공유 메모리 영역)에 연결된 뒤 OOM이 발생한 사례를 보고했습니다. 프로세스마다 페이지 테이블이 필요해 최악의 경우 PTE만 878 GB를 차지할 수 있다고 계산했습니다. 프로세스 간 페이지 테이블 공유를 위한 mshare를 제안했지만, 글 작성자가 확인한 범위에서는 병합되지 않았습니다.

비어 있는 페이지 테이블과 데이터베이스 사례

공유 매핑이 없어도 페이지 테이블이 비대해질 수 있습니다. Qi Zheng은 RSS가 590 GiB인 프로세스에서 페이지 테이블이 110 GiB까지 커진 사례를 보고했습니다. 이 작업은 jemalloc과 tcmalloc을 사용했고, 메모리를 munmap() 대신 madvise(MADV_DONTNEED)로 커널에 돌려줬습니다. MADV_DONTNEED는 데이터 페이지를 해제하고 PTE를 지우지만 페이지 테이블 자체는 남겨둘 수 있어 빈 페이지 테이블이 쌓였습니다. 이 문제를 다룬 패치는 여러 차례 수정된 뒤 2025년에 병합됐습니다.

데이터베이스에서도 비슷한 현상이 나타났습니다. Percona 사례에서는 192 GB 서버에서 PostgreSQL 공유 버퍼를 138 GiB로 설정하고 연결 80개를 사용하자, 백엔드가 캐시를 건드리는 동안 페이지 테이블이 45 MiB에서 25 GiB 이상으로 증가했습니다. 메모리 압박과 스와핑이 뒤따랐습니다. Huge Pages를 적용하자 같은 작업의 페이지 테이블은 61 MiB에 머물렀습니다. ClickHouse 사례에서는 128 GiB 서버의 32 GiB 공유 버퍼를 여러 백엔드가 읽었고, 연결 200개에서 페이지 테이블이 6.1 GiB를 차지했습니다. Huge Pages를 쓰면 같은 연결 수에서 111 MiB로 줄었습니다.

다만 Huge Pages를 확보하려면 연속된 메모리가 필요합니다. 부하가 큰 시스템에서는 요청이 실패할 수 있고, THP(Transparent Huge Pages)는 메모리 할당 과정에서 지연을 일으킬 수 있습니다. 글은 THP의 메모리 누수 가능성과 CPU 사용량 문제도 언급합니다.

NUMA에서는 지연과 메모리 비용을 맞바꿉니다

NUMA 시스템에서는 실행 스레드와 다른 노드에 페이지 테이블이 있으면 TLB 미스 뒤 원격 메모리를 읽어야 합니다. Mitosis 논문은 원격 페이지 테이블이 원격 데이터만큼 애플리케이션을 느리게 만들 수 있다고 보였고, Hydra 논문은 8소켓·8 TB 시스템에서 이 문제를 재현했습니다.

Mitosis는 페이지 테이블 트리 전체를 노드마다 복제합니다. 원격 접근을 줄이는 대신 노드 수만큼 메모리를 더 쓰고, 변경 사항을 모든 복사본에 반영해야 합니다. Hydra는 노드에서 스레드가 페이지에 접근해 폴트가 발생할 때 해당 PTE만 복제하며, 각 페이지 테이블 페이지에 복제본이 있는 노드 목록을 둡니다. 결국 NUMA 환경에서는 단일 페이지 테이블을 유지하며 원격 접근 지연을 감수하거나, 복제본을 두고 메모리와 동기화 비용을 부담해야 합니다.

원문: frn.sh / 번역·요약: Trawling