페이징과 세그멘테이션의 메모리 관리 방식 비교
페이징과 세그멘테이션의 주소 변환, 단편화, 보호·공유 특성을 비교하고 현대 시스템의 페이징 중심 설계를 정리한다.
2026-08-14 · 최초 발행 2026-01-04
고정 크기 페이지로 주소 공간을 다루는 방식
페이징은 논리 메모리를 일정한 크기의 페이지로, 물리 메모리를 같은 크기의 프레임으로 나눈 뒤 둘을 연결하는 방식이다. 논리 주소의 페이지는 물리 메모리에서 연속될 필요가 없다. 페이지 테이블이 어느 프레임에 놓였는지를 관리한다.
페이지와 프레임은 모두 동일한 크기이며, 일반적으로 4KB를 사용한다. 이 구조는 외부 단편화를 없애고 비연속적인 물리 메모리 할당을 가능하게 한다. 반면 프로세스 크기가 페이지 크기의 배수가 아니면 마지막 페이지에서 내부 단편화가 생길 수 있으며, 평균 낭비량은 1/2 페이지 크기다.
논리 주소는 페이지 번호와 오프셋으로 나뉜다. 페이지 번호로 페이지 테이블을 조회해 프레임 번호를 얻고, 오프셋을 결합해 물리 주소를 만든다.
동일한 블록 크기 덕분에 할당과 해제가 단순하고, 어떤 프레임도 페이지 저장에 사용할 수 있다. 디스크와의 교환도 페이지 단위로 처리할 수 있으며, 읽기 전용 페이지는 여러 프로세스가 함께 사용할 수 있다. 요구 페이징은 큰 프로그램을 가상 메모리에서 실행할 수 있게 한다.
대신 큰 주소 공간에서는 페이지 테이블 자체의 크기가 부담이 될 수 있다. 메모리 접근마다 페이지 테이블을 참조해야 하므로 접근 시간이 늘어날 수 있고, TLB 미스가 발생하면 성능이 저하된다. 코드와 데이터처럼 논리적으로 다른 영역이 같은 페이지 구조 안에 놓일 수 있다는 점도 페이징의 한계다.
프로그램 구조를 따라 메모리를 나누는 방식
세그멘테이션은 프로그램을 코드, 데이터, 스택, 힙처럼 의미 있는 단위로 분할한다. 각 세그먼트는 용도에 맞는 가변 크기를 가지며, 물리 메모리에는 세그먼트별로 할당된다.
세그먼트 테이블은 각 영역의 기준 주소와 한계를 보관한다. 여기에 읽기·쓰기·실행 권한을 담는 보호 비트, 사용 여부를 나타내는 유효 비트, 프로세스 간 공유 여부를 나타내는 공유 비트가 더해질 수 있다.
논리 주소는 세그먼트 번호와 오프셋으로 구성된다. 세그먼트 테이블에서 기준 주소와 한계를 찾고, 오프셋이 한계 안에 있는지 검사한다. 범위를 벗어나면 세그먼트 오류가 발생한다.
이 방식은 프로그래머가 바라보는 프로그램 구조와 메모리 경계를 맞출 수 있다. 코드 세그먼트를 여러 프로세스가 공유하거나, 세그먼트 단위로 독립적인 접근 권한을 설정하기에도 적합하다. 스택과 힙은 필요에 따라 확장할 수 있고, 경계 위반은 명확히 탐지된다.
가변 크기 할당은 외부 단편화를 만든다. First Fit, Best Fit 같은 할당 알고리즘이 필요하며, 단편화를 해소하려면 주기적인 압축이 필요할 수 있다. 세그먼트는 물리 메모리보다 클 수 없고, 테이블 관리와 한계 검사에도 비용이 든다.
단편화와 주소 변환에서 갈리는 선택
| 항목 | 페이징 | 세그멘테이션 |
|---|---|---|
| 블록 크기 | 고정 | 가변 |
| 분할 기준 | 물리적 | 논리적 |
| 프로그래머 인식 | 투명 | 명시적 |
| 외부 단편화 | 없음 | 발생 |
| 내부 단편화 | 발생 | 없음 |
| 주소 변환 | 페이지 테이블 | 세그먼트 테이블 |
메모리 활용 측면에서는 외부 단편화가 없는 페이징이 유리하다. 반면 논리적 단위로 공유와 보호를 적용해야 할 때는 세그멘테이션이 더 직접적이다. 고정 크기 블록을 다루는 페이징은 주소 변환이 빠르고, 세그멘테이션은 프로그램 구조를 드러내므로 이해하기 쉽다. 다만 주소 공간이 커지면 페이징의 테이블 오버헤드는 커질 수 있다.
리눅스, Windows, macOS 같은 대부분의 현대 운영체제는 순수 페이징을 사용한다. 순수 세그멘테이션은 Multics 같은 초기 시스템에서 쓰였고, 과거 Intel x86과 일부 임베디드 시스템은 두 방식을 결합했다. 가상 메모리와의 결합이 자연스러워 페이징이 우세하지만, 스택 실행 방지 같은 보안 기능에는 세그먼트의 경계 개념이 남아 있다.
세그먼트와 페이지를 함께 거치는 주소 변환
결합 방식에서는 논리 주소를 세그먼트 번호, 페이지 번호, 오프셋으로 해석한다. 세그먼트 테이블은 해당 세그먼트의 페이지 테이블 기준을 제공하고, 페이지 테이블은 프레임 번호를 찾는다.
세그먼트 → 페이지 → 프레임의 2단계 변환은 논리적 분할과 고정 크기 할당을 결합한다. 외부 단편화는 페이징으로 제거하고, 보호와 공유는 세그먼트 수준에서 관리할 수 있다. 그만큼 주소 변환 절차는 더 복잡하고 느려진다.
IA-32에서는 세그멘테이션이 필수였으며 CS, DS, SS, ES, FS, GS 세그먼트 레지스터와 GDT/LDT가 사용됐다. 보호 모드에서는 세그먼테이션과 페이징을 함께 쓴다. 64비트 모드에서는 세그먼트가 거의 플랫 모델로 동작해 실질적으로 페이징 중심이 된다. 모든 세그먼트 기준은 0이고 한계는 최대이며, FS/GS는 쓰레드 로컬 스토리지 등 특수 용도에 활용된다. 레거시 코드 호환성을 위해 관련 하드웨어는 남아 있다.
현대 운영체제가 페이징에 집중하는 이유
리눅스는 순수 페이징을 사용하며 세그먼트 사용을 최소화한다. Windows는 페이징 기반 가상 메모리를 사용하고, macOS는 Mach 커널의 페이징 시스템을 바탕으로 한다. Android와 iOS도 페이징을 사용하며, QNX와 VxWorks 같은 실시간 OS 역시 페이징을 선호한다.
그렇다고 논리적 메모리 영역이 사라진 것은 아니다. 코드·데이터·스택·힙이라는 구분은 계속 유지되며, NX bit와 ASLR 같은 보안 기능, 리눅스의 vm_area_struct, 파일 매핑과 공유 라이브러리도 이 관점을 활용한다.
하드웨어는 다단계 페이징과 대형 페이지를 지원하고, TLB는 수백 개 엔트리와 다중 레벨로 확장됐다. ASID/PCID 태깅은 컨텍스트 스위칭을 최적화하며, Intel MPK와 ARM MTE는 보안 기능을 확장한다. EPT와 NPT는 가상화 환경의 중첩 페이징을 지원한다.
메모리 관리 비용을 줄이는 운영 관점
페이징 시스템에서는 2MB, 1GB 대형 페이지로 TLB 효율을 높일 수 있다. THP(Transparent Huge Pages)는 대형 페이지를 자동으로 할당하며, 다단계 페이지 테이블은 메모리 오버헤드를 줄인다. 역 페이지 테이블(Inverted)은 프레임 중심으로 테이블을 관리해 크기를 축소하고, 프리페칭은 접근 패턴을 예측해 페이지를 미리 로드한다.
결합 시스템에서는 코드를 읽기 전용으로 두고 스택에 NX를 적용하는 식으로 영역별 정책을 설정할 수 있다. Copy-On-Write는 공유한 뒤 수정 시 복사하며, 메모리 맵 파일과 공유 라이브러리는 가상 메모리 매핑과 코드 영역 공유로 메모리를 절약한다. 실행과 쓰기 권한을 분리하는 데에도 세그먼트 개념이 활용된다.
애플리케이션에서는 캐시 친화적인 데이터 배치로 지역성을 높이고, 활성 페이지 집합인 워킹셋을 줄이는 접근이 중요하다. 빈번한 할당과 해제에는 메모리 풀을 고려할 수 있으며, 정렬과 패딩은 페이지 경계를 고려해 배치한다. NUMA 환경에서는 로컬 메모리 접근을 우선한다.
페이징은 외부 단편화를 제거하고 가상 메모리를 뒷받침하는 기본 구조다. 세그멘테이션은 프로그램의 논리적 경계에서 보호와 공유를 다루는 관점을 제공한다. 현대 시스템은 페이징을 기반으로 TLB와 대형 페이지를 활용하면서, 세그먼트 개념은 소프트웨어 수준의 메모리 영역 관리와 보안 정책에 남겨 두고 있다.