2026. 4. 6. 11:17ㆍ운영체제(OS)
가상기억장치와 주소 변환 기법 — 페이징, 세그먼테이션, 그리고 현대 OS
가상기억장치(Virtual Memory)의 개념과 주소 변환 기법인 페이징, 세그먼테이션, 혼합 기법까지, 그리고 현대 OS에서 실제로 어떤 방식이 쓰이는지까지 정리한다.
1. 가상기억장치 — 왜 필요한가
컴퓨터 시스템에서 실행되는 모든 프로그램은 반드시 RAM1에 올라와야 CPU가 처리할 수 있다. 그런데 프로그램이 RAM 용량보다 크거나, 여러 프로그램을 동시에 띄우면 어떻게 될까.
현재 RAM보다 큰 프로그램은
아예 실행 불가
필요할 때만 RAM으로 올라옴
더 많은 프로그램 동시 실행 가능
가상기억장치(Virtual Memory)는 이 문제를 해결하는 핵심 구조다. 보조기억장치(SSD/HDD)의 일부를 마치 RAM처럼 사용해서, 지금 당장 필요한 부분만 RAM에 올리고 나머지는 디스크에 두는 방식이다. 프로그램 입장에서는 자신이 메모리를 전부 가진 것처럼 실행되고, OS가 뒤에서 실제 RAM과 디스크 사이를 조율한다.
프로세스의 가상 주소 공간
모든 프로세스는 OS로부터 자신만의 독립적인 가상 주소 공간을 받는다. 실제로는 여러 프로그램이 RAM을 나눠 쓰고 있지만, 각 프로세스는 자기 혼자 쓰는 것처럼 보이는 큰 공간을 가진다. 이 공간은 보통 아래처럼 구역이 나뉜다.
스택과 힙 사이의 빈 공간은 가상 주소 공간에만 존재한다. 실제 RAM에는 지금 쓰고 있는 부분만 올라온다. 이 논리적인 가상 주소를 실제 RAM 주소로 바꿔주는 게 바로 주소 변환(Address Mapping)이고, 이를 어떻게 구현하느냐에 따라 페이징과 세그먼테이션으로 나뉜다.
2. 페이징(Paging) 기법
페이징은 가장 널리 쓰이는 주소 변환 방식이다. 가상 주소 공간과 물리 RAM을 모두 같은 크기의 블록으로 잘라서 관리한다. 이 블록을 가상 쪽에서는 페이지(Page), RAM 쪽에서는 프레임(Frame)이라 부른다. 보통 한 블록이 4KB다.
핵심 아이디어는 간단하다. 프로그램의 각 페이지가 RAM 어디에 있든 상관없이, 빈 프레임이면 아무 데나 넣는다. 연속된 공간이 필요 없으니 외부 단편화2가 사라진다.
페이지 맵 테이블 — 어느 프레임에 있는지 기억하는 지도
페이지들이 RAM 여기저기 흩어져 들어가다 보면, "내 프로그램의 3번 페이지가 지금 RAM 몇 번 프레임에 있지?"를 기억해야 한다. 그 역할을 하는 것이 페이지 맵 테이블이다. 각 프로세스마다 하나씩 있고, OS가 관리한다.
CPU가 페이지 2번에 접근하려 한다.
RAM 어느 프레임에 들어가도 상관없이 테이블로 추적하기 때문에, 연속된 공간이 필요 없다. 디스크에 있는 페이지에 접근하면 페이지 부재(Page Fault)가 발생해 OS가 개입한다.
페이지 부재(Page Fault) — 디스크에 있는 페이지에 접근하면
페이지 맵 테이블에서 "디스크 대기" 상태인 페이지에 접근하면 하드웨어가 OS에 신호를 보낸다. OS가 개입해서 디스크에서 해당 페이지를 RAM으로 가져오는 과정이 진행된다.
3. 세그먼테이션(Segmentation) 기법
페이징이 "크기를 무조건 같게 잘라서 관리"라면, 세그먼테이션은 프로그램을 의미 있는 단위(코드, 데이터, 스택 등)로 나눠서 관리하는 방식이다. 각 영역의 크기가 다르고, 그 크기 그대로 메모리에 할당된다.
예를 들어 코드 영역은 600바이트, 데이터 영역은 400바이트, 스택은 200바이트 이런 식으로, 실제 크기에 딱 맞게 들어간다. 페이지처럼 잘게 쪼개지 않으니 내부 낭비(내부 단편화)가 없다. 대신 크기가 제각각이라 RAM 여기저기에 빈 자투리 공간이 생길 수 있다(외부 단편화).
"코드 구역, 50번째 바이트"
코드 구역이 RAM 어디서 시작?
= 실제 RAM 주소
→ 에러 발생, 다른 구역 침범 방지
| 페이징 | 세그먼테이션 | |
|---|---|---|
| 분할 단위 | 고정 크기 (4KB) | 가변 크기 (실제 크기) |
| 내부 낭비 | 있음 (마지막 페이지) | 없음 |
| 외부 낭비 | 없음 | 있음 (자투리 공간) |
| 현대 사용 | ✅ 주력 | ⚠️ 거의 안 씀 |
4. 세그먼테이션-페이징 혼합 기법
두 방식의 장점을 합치자는 아이디어다. 프로그램을 먼저 논리 구역(세그먼트)으로 나누고, 그 각 구역을 다시 페이지로 잘게 쪼개는 방식이다. 사용자가 볼 때는 코드/데이터/스택 같은 논리 구역으로 보이고, 실제 메모리에서는 페이지 단위로 관리된다.
(세그먼트 테이블)
(페이지 테이블)
주소 변환을 두 번 거치다 보니 구조가 복잡해진다. 그래서 현대에는 이 방식보다 페이징 단일 방식이 훨씬 널리 쓰인다.
5. 현대 OS는 어떻게 하는가
교재에서 세 기법을 동등하게 다루지만, 현대 OS에서 실제로 쓰이는 건 사실상 페이징 하나다.
실제 RAM 접근 흐름 — 4단계 주소 변환
현대 64비트 시스템에서 하나의 메모리 접근이 일어날 때 내부에서는 이런 흐름이 진행된다. 교재의 단순한 1단계 테이블 조회보다 단계가 더 많지만, 덕분에 훨씬 큰 주소 공간을 효율적으로 관리할 수 있다.
가상 주소 생성
최근 변환 캐시
즉시 완료 ✅
Demand Paging — 현대의 핵심 전략
현대 OS는 메모리 할당을 최대한 미룬다. C#에서 new를 하거나, C에서 malloc()을 해도 실제 RAM은 바로 안 준다. 가상 주소 공간만 예약해두고, 실제로 그 주소를 처음 읽거나 쓸 때 그제서야 RAM 프레임을 할당한다. 이때 발생하는 page fault가 바로 그 시점이다.
(100MB 요청)
예약 (즉시)
(그때서야)
100MB를 요청해도 실제로 10MB만 쓰면 RAM은 10MB만 소모된다. 그래서 여러 프로그램을 동시에 띄워도 RAM이 버티는 것이다.
6. Unity 개발자 입장에서 보면
Unity 앱이 실행되면 OS는 Unity 프로세스에 독립적인 가상 주소 공간을 제공한다. C# 객체들이 올라가는 Managed Heap도 이 가상 주소 공간 안에 있다. 여기서 페이징 개념이 직접 연결된다.
- Boehm GC는 non-compacting: Unity의 GC는 안 쓰는 객체를 수집해도 남은 객체들을 이동시키지 않는다. 빈 슬롯이 흩어진 채로 남는 게 힙 내부 단편화다. 큰 배열을 할당하려는데 연속 공간이 없으면 힙이 늘어난다.
- 가상 주소 공간은 OS에 안 돌려줌: Managed Heap이 한 번 커지면 GC가 돌아도 그 가상 주소 공간은 OS에 반환되지 않는다. Profiler에서 Reserved가 줄지 않는 이유다.
- NativeArray는 연속 물리 메모리:
NativeArray<T>는 페이지 경계에 정렬된 연속 메모리를 쓴다. GC 없이 캐시 효율도 높아서 Job System과 궁합이 좋다.
// Managed Heap — GC 관리, non-compacting 단편화 가능
var enemies = new List<Enemy>();
// NativeArray — 연속 물리 메모리, GC 없음, 캐시 친화적
using var positions = new NativeArray<float3>(1000, Allocator.Persistent);
📎 용어 설명
- RAM (Random Access Memory) — 주기억장치. CPU가 직접 접근하는 메모리. 전원을 끄면 내용이 사라진다.
- 외부 단편화 — 빈 공간이 충분한데 연속되지 않아서 큰 프로그램을 넣지 못하는 현상. 퍼즐 조각처럼 조각조각 흩어진 빈 공간.
'운영체제(OS)' 카테고리의 다른 글
| [OS] 하드디스크 구조와 디스크 스케줄링 알고리즘 - 15 (0) | 2026.04.07 |
|---|---|
| [OS] 페이지 교체 알고리즘, 워킹셋, 스래싱 - 14 (0) | 2026.04.06 |
| [OS] 메모리 단편화(Fragmentation)와 배치 전략 - 12 (0) | 2026.04.03 |
| [OS] 기억장치 개요와 주기억장치 할당 기법 - 11 (0) | 2026.03.27 |
| [OS] 입출력 프로그래밍 - 10 (1) | 2026.03.26 |