✅ 가상 메모리 기법 (Virtual Memory)
: 프로세스 전체가 메모리에 올라가지 않더라도 실행할 수 있도록 지원하는 메모리 관리 기법
프로그램을 실행하기 위해서는 이를 메모리(RAM)에 적재해야 한다.
하지만 용량이 큰 프로세스나 다중 프로그래밍 상황에서는 물리 메모리만으로 부족할 수 있다.
이 문제를 해결하기 위해 애플리케이션을 실행하는데 최소한 얼마만큼의 메모리가 필요한가에 집중하는 가상 메모리 기법이 등장했다.
- 디스크의 일부 영역(스왑 공간)을 메모리처럼 활용
- 프로그램은 전체 메모리를 사용하는 듯 보이지만, 실제로는 일부만 물리 메모리에 존재
- CPU는 TLB, MMU를 사용하여 가상 주소 -> 물리 주소로 변환
- MMU (Memory Management Unit): 가상 주소를 물리 주소로 변환해 주는 하드웨어
- TLB (Translation Lookaside Buffer): 최근 변환된 주소 정보를 캐싱하여 변환 속도를 높이는 고속 메모리
- 일반적으로 Paging 또는 Segmentation 기반으로 동작

💡 장점
- 실제 메모리보다 큰 프로그램도 실행 가능
- 여러 프로세스를 동시에 실행하여 CPU 활용률 향상
- 개발자는 메모리 용량을 신경 쓰지 않고 코드 작성 가능
🚨 단점
- 물리 메모리로 실행하는 것보다 디스크 접근이 느림
- Page Fault 발생 시 I/O 지연이 큼
- 스레싱(Thrashing) 발생 가능
📍 가상 주소 공간

- 각 프로세스는 자신만의 연속된 가상 주소 공간을 가짐
- 보통 0번지부터 시작
- 가상 주소 공간은 연속되어 있지만, 실제 물리 메모리는 비연속적인 프레임으로 할당
- MMU에 의해 물리 주소로 변환
- ex) 한 프로그램이 100KB의 가상 메모리를 요구하지만, 실제 실행에 필요한 text/data/heap/stack이 40KB라면?
- 실제 물리 메모리에는 40KB 만 올라가 있고, 나머지 60KB는 필요시 디스크에서 가져옴
✅ 페이징 (Paging)
: 페이지 단위의 논리-물리 주소 관리 기법
- 외부 단편화를 해결하기 위한 비연속 메모리 할당 기법
- 가상 주소 공간을 고정 크기의 페이지로 나눔
- 물리 메모리에는 프레임(Frame)이라는 동일 크기 단위로 저장
- 페이지 순서와 프레임 순서는 무관함
🚨 단점
- 내부 단편화 문제의 비중이 늘어날 수 있음
- ex) 페이지 크기가 1024B, 프로세스 A가 3172B 메모리를 요구
- 총 4개의 프레임 필요 => 4096B
- 마지막 프레임에는 924B(1024-100)나 되는 여유 공간이 남아 내부 단편화 발생
- ex) 페이지 크기가 1024B, 프로세스 A가 3172B 메모리를 요구
📍 Page Fault
: CPU가 참조하려는 페이지가 현재 메모리에 없는 경우

💡 처리 흐름
- 프로세스의 내부 테이블을 확인해 유효한 주소인지 확인
- 유효한데 아직 메모리에 없다면 Page Fault / 무효하면 프로세스 중단
- 메모리에 올릴 빈 프레임 확보
- 디스크에서 필요한 페이지를 읽어와 확보한 프레임에 적재 (오랜 시간이 거리는 I/O 작업)
- 페이지 테이블 업데이트
- Page Fault로 멈췄던 명령어 재실행
📍 페이지 번호 + 오프셋
페이징 방식에서 가상 주소 공간은 페이지 번호, 페이지 오프셋 두 부분으로 나뉜다.

🏷️ 페이지 번호 (Page Number)
: 페이지 테이블을 조회할 때 사용
- 가상 주소가 몇 번째 페이지인지를 나타냄
- MMU는 페이지 번호를 사용해 페이지 테이블을 조회
🏷️ 페이지 오프셋 (Page Offset)
: 참조되는 프레임 안에서의 위치
- 페이지 테이블은 각 프레임의 물리적 시작 주소를 가짐
- 페이지 번호로 조회한 페이지 안 에서의 세부 위치는 오프셋을 의미
📍 논리 주소 -> 물리 주소 변환

- 페이지 번호 p를 페이지 테이블의 인덱스로 활용
- 페이지 테이블에서 프레임 번호 f 추출
- 프레임 내부의 정확한 데이터를 찾기 위해 오프셋 사용
- 최종 물리 주소 = 프레임 번호 f의 시작 주소 + 오프셋 d
페이지 테이블은 보통 메인 메모리에 저장된다.
📍 페이지 크기
- 작으면?
- 페이지 수가 증가 -> 페이지 테이블의 크기도 커짐 -> 메모리 오버헤드 증가
- 하지만 메모리 낭비 적음, 필요한 데이터만 가져와 Page Fault 줄일 수 있음
- 크면?
- 페이지 수 적음 -> 페이지 테이블 작아짐
- 불필요한 데이터까지 로딩 -> 내부 단편화 발생률 증가, 작업 세트를 다 담지 못하면 Page Fault 증가
| 페이지 크기 | 장점 | 단점 |
| 작을 때 | 메모리 낭비 적음 Page Fault 줄어들 수 있음 |
페이지 수 증가 -> 테이블 커짐 관리 오버헤드 증가 |
| 클 때 | 페이지 테이블 작아짐 I/O 효율 증가 |
내부 단편화 발생률 커짐 불필요한 데이터 적재 가능 접근 패턴에 따라 Page Fault 가능 |
✅ TLB (Translation Look-Aside Buffer)
: 자주 쓰는 페이지 테이블 정보를 CPU 내부에 빠르게 캐싱해 두는 공간
페이징 기법을 사용할 때, 가상 주소를 물리 주소로 변환하려면 보통 두 번의 메모리 접근이 필요하다.
- 페이지 테이블을 읽어 프레임 번호를 찾고
- 그 프레임 번호를 바탕으로 실제 데이터를 읽기
이 과정은 느릴 수밖에 없기 때문에, 이를 해결하기 위해 등장한 것이 바로 TLB이다.
- 하드웨어로 된 작은 캐시 메모리
- 빠르게 처리하기 위해 CPU 내부에 위치
- <페이지 번호, 프레임 번호> 형식의 쌍으로 저장
- 가상 주소가 들어오면 TLB는 페이지 번호를 내부 항목들과 동시에 비교
- 단점은 크기가 작다는 것

- TLB hit(페이지 번호가 TLB에 존재): Page Table 거쳐갈 필요 없이 가상 주소를 실제 주소로 변환
- TLB miss(페이지 번호가 TLB에 없음): 메모리에 있는 Page Table에서 가상 주소에 해당하는 정보를 가져와서 실제 주소로 변환
📍 TLB 동기화 문제: ASID
현대 시스템에서는 여러 개의 프로세스가 번갈아 실행되고, CPU 코어도 여러 개인 경우가 많다.
이에 따라 한 프로세스의 TLB 항목이 다른 프로세스에서 잘못 사용될 위험이 있다.
그 이유는 TLB를 사용할 때 Context Switching이 발생하는 상황을 보면 쉽게 이해할 수 있다.
- 현재 실행되고 있는 프로세스 A는 TLB 테이블에 다음과 같이 저장되어 있다.
- <페이지 번호 10, 프레임 번호 42>
- 컨텍스트 스위칭이 발생해 프로세스 B가 실행되었다고 하자.
- 프로세스 B 역시 페이지 번호 10을 갖고 있지만, 이 경우 매핑된 프레임은 다르다: <페이지 번호 10, 프레임 번호 88>
- 문제는, TLB는 기본적으로 어떤 프로세스의 항목인지 식별하지 못한다는 점이다.
- 즉, A와 B 모두 페이지 번호 10을 사용하더라도, 서로 다른 의미를 가진다는 사실을 TLB는 알 수 없다.
- 그 결과 프로세스 B가 자신의 페이지 번호 10을 참조하려다가, 실제로는 TLB에 남아 있던 프로세스 A의 페이지 번호 10 → 프레임 번호 42 정보를 잘못 참조할 수 있다.
그리고 이를 해결하기 위한 기법으로는 다음과 같다.
🏷️ 전통적인 해결책: TLB Flush
: Context Switching 시 TLB를 모두 비워(flush) 버리는 방식
하지만 이 방식은 매번 전부 지우고 다시 채워야 하므로 성능 저하가 상당히 크다.
🏷️ ASID (Address Space Identifier)
: TLB에 저장된 항목이 어느 프로세스의 것인지 식별해 주는 태그
- TLB에 <페이지 번호, 프레임 번호> 외에 ASID도 함께 저장
- 주소 변환 요청 시, MMU는 현재 실행 중인 프로세스의 ASID와 TLB의 ASID가 일치하는 항목만 유효한 것으로 판단
- 일치하지 않으면 TLB miss
이 방식은 성능 저하 없이 주소 보호를 보장한다.
✅ 세그멘테이션 (Segmentation)
: 사용자/프로그래머 관점의 메모리 관리 기법
- 페이지와 달리 세그먼트(Segment)는 서로 다른 크기를 가짐
- 메모리 사용할 시점에 나눠 할당
- 세그먼트 테이블에는 각 세그먼트의 시작 물리 주소와 세그먼트의 길이를 저장
🚨 단점
- 서로 다른 크기의 세그먼트가 적재/해제되며 외부 단편화 발생 가능
✅ 스레싱 (Thrashing)
: 프로세스 처리 시간보다 페이지 교체 시간이 더 많아져 성능이 저하되는 문제
📍 발생 원인
- 프레임 수가 부족하여 계속 Page Fault 발생
- 프로세스가 유의미한 작업을 하지 못하고 계속 페이지 교체만 수행
💡 완화 방법
스레싱이 일어났다는 의미는, 각 프로세스가 필요로 하는 최소한의 프레임 수를 보장해주지 않았기 때문이다.
- 정적 프레임 할당
- 균등 할당: 모든 프로세스에 동일한 프레임 수
- 단점: 여전히 Page Fault 발생 가능성 존재
- 비례 할당: 프로세스 크기에 비례해 프레임 분배
- 단점: 크기가 작은 프로세스임에도, 많은 프레임을 필요로 한 경우도 존재
- 균등 할당: 모든 프로세스에 동일한 프레임 수
- Working Set 모델: 프로세스마다 자주 사용하는 페이지 집합만큼 프레임 보장
- 최근 일정시간 동안 참조된 페이지들을 집합으로 만들고, 이 집합에 있는 페이지들을 물리 메모리에 유지
- Page Fault Frequency (PFF) 기반 조절
✨ 추가 질문
[ 페이지 vs 프레임 ]
- 페이지(Page): 프로세스의 논리적 주소 공간 단위
- 프레임(Frame): 물리 메모리의 할당 단위
페이지와 프레임은 일대일로 대응된다.
[ 가상 메모리가 가능한 이유가 무엇일까요? ]
가상 주소를 물리 주소로 변환해 주는 MMU와, 페이징 같은 비연속 메모리 기법 덕분에 가능하다.
가상 주소는 MMU에 의해 페이지 번호와 오프셋으로 분리되고, 페이지 번호는 페이지 테이블을 참조하여 해당 페이지가 매핑된 물리 메모리 프레임을 찾는다.
[ 페이지 크기가 커지면, 페이지 폴트가 더 많이 발생한다고 할 수 있나요? ]
항상 그런 것은 아니다.
- 페이지 크기가 커지면 한 번에 더 많은 데이터를 가져올 수 있어 순차적으로 접근하는 프로그램에서는
오히려 페이지 폴트가 줄어들 수 있다.
- 하지만 만약 프로그램이 다양한 위치를 불규칙하게 접근하는 경우에는
불필요한 데이터까지 메모리에 올라오고 작업에 필요한 페이지 수를 충분히 담지 못해 페이지 폴트가 증가할 수 있습니다.
[ 세그멘테이션 방식을 사용하고 있다면, 가상 메모리를 사용할 수 없을까요? ]
사용 가능하다.
필요한 세그먼트만 메모리에 적재하는 방식으로 가상 메모리를 구현할 수 있다.
단, 세그먼트는 크기가 가변적이기 때문에 외부 단편화가
[ 어떤 주소공간이 있을 때, 이 공간이 수정 가능한지 확인할 수 있는 방법이 있나요? ]
페이지 테이블 엔트리에는 담기는 정보로 보호 비트가 있다. 보호 비트를 통해 해당 페이지가 읽고 쓰기가 모두 가능한 페이지인지, 혹은 읽기만 가능한 페이지인지를 나타낼 수 있습니다.
[ 32비트에서, 페이지의 크기가 1kb이라면 페이지 테이블의 최대 크기는 몇 개일까요? ]
- 32비트 -> 전체 주소 범위는 2^32 = 4GB (1GB = 2^30)
- 페이지 크기는 1KB = 2^10
- 최대 페이지 수 = 2^32 / 2^10 = 2^22 (개)
=> 페이지 테이블의 최대 크기는 2^22 개다.
[ 32비트 운영체제는 램을 최대 4G까지 사용할 수 있습니다. 이 이유를 페이징과 연관 지어서 설명해 주세요. ]
32비트 주소 공간은 최대 2^32 개의 주소를 표현할 수 있다.
페이징은 이 2^32개의 가상 주소를 페이지 테이블을 통해 물리 주소로 변환한다.
결국 가상 주소 자체가 32비트로 제한되어 있기 때문에, 접근 가능한 물리 메모리도 2^32 = 4GB가 최대이다.
[ C/C++ 개발을 하게 되면 Segmentation Fault라는 에러를 접할 수 있을 텐데, 이 에러는 세그멘테이션/페이징과 어떤 관계가 있을까요? ]
Segmentation Fault는 프로세스가 허용되지 않은 메모리 영역에 접근할 때 발생하는 오류이다.
- 페이징에서의 Segmentation Fault: 배열의 범위를 초과하거나 Null 포인터를 참조할 때 발생 가능
- 세그멘테이션에서의 Segmentation Fault: 허용되지 않은 세그먼트에 접근할 경우
[ TLB를 쓰면 왜 빨라지나요? ]
주소를 변환할 때 매번 메모리에 있는 페이지 테이블을 읽으면 속도가 느려진다.
TLB는 CPU 내부에 있어 메모리보다 빠르게 접근할 수 있고, 자주 참조되는 페이지들은 TLB에서 미리 변환된 결과를 가져오면 주소 변환 시간이 메모리 접근 시간보다 훨씬 짧아진다.
[ TLB와 MMU는 어디에 위치해 있나요? ]
TLB와 MMU는 모두 CPU 내부에 위치한다.
MMU는 TLB를 포함하고 있다.
[ 코어가 여러 개라면, TLB는 어떻게 동기화할 수 있을까요? ]
- TLB flush: 컨텍스트 스위칭 시, TLB를 전부 비움
- ASID: TLB에 저장된 항목이 어느 프로세스의 것인지 식별해 주는 태그를 사용
[ TLB 관점에서, Context Switching 발생 시 어떤 변화가 발생하는지 설명해 주세요. ]
1. Context Switching 발생
2. MMU가 현재 실행 중인 프로세스의 ASID 값을 갱신
3. TLB 항목 중 현재 ASID와 일치하는 항목만 유효하게 인식
4. 일치하는 항목이 있으면 hit, 없으면 miss 발생 후 페이지 테이블 참조
'⚙️ CS > 운영체제' 카테고리의 다른 글
| [운영체제] 동기/비동기 & 블로킹/논블로킹 (0) | 2025.05.07 |
|---|---|
| [운영체제] 페이지 교체 알고리즘 (0) | 2025.05.06 |
| [운영체제] 메모리 할당 방식 (1) | 2025.04.30 |
| [운영체제] 캐시 메모리 (Cache Memory) (1) | 2025.04.29 |