OS의 메모리 관리는 프로그램을 안전하고 효율적으로 실행하기 위해 필요
현대 OS는 logical, physical 주소를 분리하고 바인딩과 MMU를 통해 주소를 동적으로 변환함
CPU는 디스크에 있는 프로그램을 직접 실행할 수 없다.
반드시 메모리(RAM)에 올라와야 실행 가능
이 문제를 해결하기 위해 OS는 다음을 보장해야 한다.
이 요구사항의 해답이 바로 메모리 관리다.
CPU는 실제 메모리 주소를 직접 다루지 않는다.
Logical Address
→ 프로그램이 보는 주소 (0부터 시작)
Physical Address
→ 실제 RAM의 주소
이 둘을 분리하는 이유는 안전성과 유연성 때문이다.
CPU ──(Logical Address)──▶ MMU ──▶ Physical Memory
MMU는 하드웨어다.
모든 메모리 접근은 반드시 MMU를 통과한다.
MMU의 핵심 역할:
Physical Address = Base + Logical Address
그리고 동시에 보호 검사를 수행한다.
각 프로세스는 두 개의 값만 알고 있다.
접근 조건:
0 ≤ Logical Address < Limit
하나라도 어기면 즉시 trap (강제 종료)
[Process A]
Base = 20000
Limit = 6000
Logical = 5000
→ Physical = 25000 (허용)
Logical = 7000
→ Limit 초과 → Trap
핵심 개념:
OS는 주소 변환 + 보호를 동시에 처리한다.
“주소가 언제 확정되는가?”
Logical Address ≠ Physical Address
→ 매 접근마다 MMU 변환
프로그램 전체를 메모리에 올릴 필요 없음
실제 호출되는 함수(루틴)만 올림
메모리 낭비를 줄이고 더 많은 프로세스를 수용 가능
➡ 프로그램 전체가 메모리에 있을 필요는 없다.
라이브러리를 실행 파일에 포함하지 않는다.
| 구분 | Static | Dynamic |
|---|---|---|
| 포함 시점 | 컴파일 | 실행 |
| 실행 파일 크기 | 큼 | 작음 |
| 메모리 효율 | 낮음 | 높음 |
| 라이브러리 공유 | 불가 | 가능 |
여러 프로그램이 실행되면 메모리가 군데군데 비게(fragmentation) 됨
큰 프로그램을 올릴 공간이 부족해짐
→ 따라서 프로그램을 다른 위치로 옮기거나 스왑아웃해 정리할 필요가 있음
[ A ][ 빈 ][ B ][ 빈 ][ C ]
스와핑(Swapping) 과정:
프로세스 A를 디스크로 내림 (swap out)
다른 프로세스 B를 메모리로 올림 (swap in)
주소 바인딩이 execution time일 때만 위치 변경 가능
“왜 Logical Address가 필요한가?”
→ 보호, 이동성, 동시 실행 때문
메모리는 한정된 자원이다.
운영체제는 동시에 실행되는 여러 프로세스에게 메모리를 안전하고 효율적으로 분배해야 한다.
초기의 접근 방식은 단순했다.
“프로세스 하나당, 연속된 메모리 덩어리 하나”
이 방식은 구현이 쉽지만, 시간이 지날수록 메모리를 잘 쓰지 못하는 구조적 문제를 드러냈다.
이 문제를 해결해 나가는 과정이 바로 메모리 관리 기법의 발전사다.
하나의 프로세스는 연속된 물리 메모리 영역을 통째로 할당받는다.
[ OS ][ P1 ][ P2 ][ Free ][ P3 ]
각 프로세스는 두 값만 알면 된다.
주소 변환도 단순하다.
Physical Address = Base + Logical Address
프로세스가 종료되면 해당 영역은 Free List로 반환된다.
문제는 시간이 지나면서 Free List가 여러 크기의 조각으로 나뉜다는 점이다.
이때 어디에 프로세스를 배치할지를 정하는 전략이 필요하다.
First Fit
→ 처음으로 들어갈 수 있는 공간
→ 빠르고 실용적, 실제로 가장 많이 사용됨
Best Fit
→ 가장 딱 맞는 공간
→ 낭비는 줄지만, 작은 조각이 많이 남음
Worst Fit
→ 가장 큰 공간
→ 이론적 의미는 있으나 실무 성능은 낮음
메모리를 전부 합치면 충분한데
연속된 공간이 없어 프로세스를 올릴 수 없는 상황.

이미 할당된 블록 내부에서 남는 공간.

메모리를 한쪽으로 몰아 연속 공간을 만드는 방식.
하지만 실행 중인 프로세스를 이동해야 하므로 비용이 매우 크다.
👉 여기서 자연스럽게 요구되는 조건이 있다.
Execution-time Binding
= 실행 중에도 주소를 바꿀 수 있어야 한다.
연속 할당의 문제는 “연속이어야 한다”는 가정에서 시작된다.
Paging은 이 가정을 완전히 깨버린다.
프로그램은 연속된 것처럼 보이지만,
실제로는 메모리 곳곳에 흩어져 배치된다.
논리 주소는 두 부분으로 나뉜다.
[ Page Number | Offset ]
동작 흐름:
➡ 외부 단편화는 완전히 사라진다.
Paging은 메모리를 아끼는 대신 관리 비용을 낳는다.
예를 들어:
→ Page Table 엔트리 약 100만 개
→ 프로세스 하나당 수 MB의 메타데이터 필요
이 자체가 또 다른 낭비다.
Page Table은 메모리에 있다.
즉, 주소 변환을 위해 메모리를 한 번 더 접근해야 한다.
이를 해결하기 위해 등장한 것이 TLB (Translation Lookaside Buffer)다.

TLB hit rate가 높아질수록
주소 변환 비용은 메모리 접근 1회 수준으로 수렴한다.
TLB 없는 Paging이 느리다