컴퓨터에서 실행되는 프로그램의 수는 계속 늘어나지만 물리적으로 장착된 램의 용량은 유한하다. 이 근본적인 한계를 해결하기 위해 현대 운영체제는 가상 메모리라는 기법을 사용하며, 그 핵심 구현 방식이 바로 페이징이다. 가상 메모리와 페이징의 동작 원리를 이해하면 프로그램이 실행되는 동안 메모리가 어떻게 배분되고, 주소가 어떻게 변환되며, 메모리 부족 상황에서 시스템이 어떤 방식으로 대응하는지를 체계적으로 파악할 수 있다. 이 글에서는 페이지와 프레임의 개념부터 주소 변환 과정, 페이지 테이블과 TLB의 역할, 페이지 교체 알고리즘, 그리고 단편화 문제에 이르기까지 운영체제 메모리 관리의 핵심 원리를 순서대로 살펴본다.

▍ 가상 메모리의 개념과 등장 배경
가상 메모리는 프로세스가 실제 물리 메모리의 용량과 무관하게, 마치 훨씬 더 큰 메모리 공간을 독점적으로 사용하는 것처럼 동작하도록 만드는 메모리 관리 기법이다. 프로그램 입장에서는 자신이 사용하는 주소 공간이 0번지부터 연속적으로 이어지는 것처럼 보이지만, 실제로는 그 주소들이 물리 메모리의 여러 곳에 흩어져 매핑되어 있거나 일부는 아예 메모리에 올라오지 않은 상태로 존재할 수 있다.
이러한 개념이 등장하게 된 배경에는 초기 컴퓨터 시스템의 구조적 한계가 자리한다. 프로그램 전체가 물리 메모리에 적재되어야만 실행이 가능했던 시절에는, 램 용량보다 큰 프로그램을 아예 실행할 수 없었다. 여러 사용자가 동시에 컴퓨터 자원을 나눠 쓰는 시분할 시스템이 보급되면서 한정된 메모리를 여러 프로세스가 동시에, 그리고 안전하게 사용할 수 있는 방법이 필요해졌고, 그 해답으로 가상 메모리 개념이 발전했다.
가상 메모리를 구현하는 방식에는 크게 페이징과 세그멘테이션 두 가지 접근이 있다. 세그멘테이션은 프로그램을 코드, 데이터, 스택과 같은 논리적 의미 단위로 나누어 관리하는 방식으로 프로그램의 구조를 잘 반영한다는 장점이 있지만, 세그먼트의 크기가 제각각이기 때문에 메모리 할당과 회수를 반복하다 보면 빈 공간이 조각조각 남는 외부 단편화 문제에서 자유롭지 못하다. 반면 페이징은 메모리를 일정한 크기의 블록으로 균일하게 나누어 관리하기 때문에 이러한 외부 단편화 문제를 근본적으로 해소할 수 있어, 오늘날 대부분의 범용 운영체제는 페이징 방식을 주된 가상 메모리 구현 기법으로 채택하고 있다.
▍ 페이징의 기본 원리: 페이지와 프레임
페이징은 프로세스가 사용하는 논리 주소 공간을 페이지라는 일정한 크기의 단위로 나누고, 물리 메모리 역시 같은 크기의 프레임이라는 단위로 나눈 뒤, 각 페이지를 임의의 빈 프레임에 매핑하는 방식으로 동작한다. 페이지와 프레임의 크기는 항상 동일하며, 일반적으로 4킬로바이트가 널리 쓰이지만 시스템 구조와 용도에 따라 다른 크기가 사용되기도 한다.
예를 들어 어떤 프로세스가 8킬로바이트의 메모리 공간을 요청했다고 가정하면, 이 공간은 4킬로바이트짜리 페이지 두 개로 분할된다. 운영체제는 물리 메모리 상에서 비어 있는 프레임 두 개를 찾아 각각의 페이지를 배정하는데, 이때 두 프레임이 물리적으로 서로 인접해 있을 필요는 전혀 없다. 이것이 페이징 방식의 핵심으로, 프로세스에게는 연속된 하나의 공간처럼 보이지만 실제로는 메모리 곳곳에 흩어진 조각들의 집합일 수 있다는 점이다.
이러한 방식 덕분에 물리 메모리에 남아 있는 공간이 여러 조각으로 나뉘어 있더라도, 그 조각들을 모두 활용해 프로세스를 적재할 수 있다. 연속된 넓은 공간이 없어서 프로그램을 실행하지 못하는 외부 단편화 문제가 페이징 환경에서는 원천적으로 발생하지 않는 것이다. 다만 프로세스의 크기가 페이지 크기의 정확한 배수가 아닌 경우, 마지막 페이지에서는 실제 사용량보다 남는 공간이 생길 수 있는데 이를 내부 단편화라고 부르며 뒤에서 다시 다룬다.

▍ 주소 변환 과정: 논리 주소에서 물리 주소로
CPU가 실행 중인 프로그램은 항상 논리 주소, 즉 가상 주소만을 사용한다. 이 논리 주소는 페이지 번호와 오프셋이라는 두 부분으로 구성된다. 페이지 번호는 접근하려는 데이터가 몇 번째 페이지에 속해 있는지를 나타내고, 오프셋은 그 페이지 내부에서 해당 데이터가 페이지 시작 지점으로부터 얼마나 떨어져 있는지를 나타낸다.
CPU가 특정 논리 주소에 접근하려 하면, 먼저 페이지 번호를 이용해 페이지 테이블을 조회하여 해당 페이지가 매핑된 프레임 번호를 찾아낸다. 이후 프레임의 시작 주소에 오프셋 값을 더하면 실제 물리 주소가 계산된다. 논리 주소의 오프셋 값과 물리 주소의 오프셋 값은 항상 동일하다는 점이 중요한데, 이는 페이지와 프레임의 크기가 같기 때문에 성립하는 특성이다.
이 주소 변환 작업은 소프트웨어가 아니라 CPU 내부 또는 근처에 위치한 메모리 관리 장치, 즉 MMU라는 전용 하드웨어가 담당한다. MMU는 논리 주소를 물리 주소로 실시간 변환할 뿐만 아니라, 해당 페이지에 대한 읽기·쓰기·실행 권한을 검사하여 프로세스가 허용되지 않은 영역에 접근하려 할 때 예외를 발생시키는 메모리 보호 기능도 함께 수행한다. 이러한 하드웨어 지원이 있기에 페이징으로 인한 주소 변환 과정이 시스템 전체 성능에 미치는 부담을 최소화할 수 있다.
▍ 페이지 테이블과 TLB의 역할
프로세스의 페이지들이 물리 메모리의 어느 프레임에 위치하는지를 기록해 두지 않으면 CPU는 다음에 실행할 명령어나 참조할 데이터가 실제로 어디에 있는지 알 수 없다. 이 정보를 담고 있는 자료구조가 페이지 테이블이며, 각 프로세스는 자신만의 고유한 페이지 테이블을 가지고 이 테이블 자체도 메모리에 적재되어 있다.
CPU 내부에는 현재 실행 중인 프로세스의 페이지 테이블이 메모리 어디에 위치하는지를 가리키는 레지스터가 존재하며, 문맥 교환이 일어나 다른 프로세스가 실행될 때마다 이 레지스터의 값이 새로운 프로세스의 페이지 테이블 주소로 갱신된다. 페이지 테이블의 각 항목에는 단순히 프레임 번호만 담기는 것이 아니라, 해당 페이지가 현재 물리 메모리에 실제로 존재하는지를 나타내는 유효 비트, 읽기와 쓰기 등의 접근 권한을 나타내는 보호 비트, 최근에 참조되었는지를 나타내는 참조 비트, 내용이 변경되었는지를 나타내는 수정 비트 등 여러 상태 정보가 함께 저장된다.
그런데 페이지 테이블은 메모리 상에 존재하기 때문에, CPU가 데이터 하나를 읽으려면 먼저 페이지 테이블에 접근해 프레임 번호를 확인한 뒤 다시 실제 데이터가 있는 프레임에 접근해야 하는 이중의 메모리 접근이 발생한다. 이는 메모리 접근 속도를 사실상 절반으로 떨어뜨리는 문제를 야기한다. 이를 완화하기 위해 도입된 것이 변환 색인 버퍼, 즉 TLB이다. TLB는 CPU 가까이에 위치한 고속 캐시 메모리로, 최근에 사용된 페이지 번호와 프레임 번호의 매핑 정보를 미리 저장해 둔다.
CPU가 주소 변환을 요청할 때 원하는 매핑 정보가 TLB에 있으면 이를 TLB 히트라 하며, 이 경우 메모리에 있는 페이지 테이블을 거치지 않고 즉시 물리 주소를 얻을 수 있어 처리 속도가 크게 빨라진다. 반대로 TLB에 해당 정보가 없으면 TLB 미스가 발생하고, 이때는 어쩔 수 없이 메모리의 페이지 테이블까지 접근해 정보를 가져온 뒤 TLB에도 갱신해 두는 절차를 거친다.

▍ 요구 페이징과 페이지 폴트의 처리 과정
가상 메모리의 진정한 이점은 프로세스의 모든 페이지를 한꺼번에 메모리에 올리지 않아도 실행이 가능하다는 점에서 드러난다. 요구 페이징은 프로그램이 실제로 필요로 하는 시점에만 해당 페이지를 물리 메모리로 가져오는 방식으로, 이를 통해 물리 메모리보다 큰 프로그램도 실행할 수 있고 초기 실행 속도와 메모리 활용 효율도 개선된다.
요구 페이징 환경에서 CPU가 특정 논리 주소에 접근했을 때, 페이지 테이블의 유효 비트가 그 페이지는 현재 메모리에 없고 보조기억장치의 스왑 영역에 있음을 나타내는 경우, 페이지 폴트라는 예외가 발생한다. 이때 운영체제는 제어권을 넘겨받아 다음과 같은 절차를 진행한다. 먼저 해당 페이지가 저장된 보조기억장치의 위치를 확인하고, 물리 메모리에 빈 프레임이 있는지를 점검한다.
빈 프레임이 있다면 그 자리에 페이지를 읽어 오면 되지만, 메모리가 가득 차 있다면 기존에 적재된 페이지 중 하나를 내보내는 페이지 교체 작업이 먼저 이루어져야 한다. 내보낼 페이지의 수정 비트가 변경되었음을 나타낸다면 디스크에 그 내용을 다시 기록한 뒤 자리를 비우고, 이후 필요한 페이지를 보조기억장치에서 읽어 들여 해당 프레임에 적재한다. 마지막으로 페이지 테이블의 유효 비트를 갱신하고 프레임 번호를 기록한 다음, 중단되었던 명령어를 처음부터 다시 실행한다. 이 과정에서 물리 메모리로 옮기는 것을 스왑 인, 반대로 내보내는 것을 스왑 아웃이라 부르며, 페이징 환경에서는 이 작업이 프로세스 전체가 아니라 페이지 단위로 이루어진다는 점이 특징이다.

▍ 페이지 교체 알고리즘: 무엇을 내보낼 것인가
물리 메모리에 빈 프레임이 없는 상태에서 새로운 페이지를 적재해야 할 때, 어떤 페이지를 내보낼지 결정하는 문제는 시스템 성능에 직접적인 영향을 미친다. 잘못된 페이지를 내보내면 곧이어 그 페이지가 다시 필요해져 페이지 폴트가 반복적으로 발생할 수 있기 때문이다.
가장 단순한 방식은 먼저 들어온 페이지를 먼저 내보내는 선입선출 방식이다. 구현이 간단하다는 장점이 있지만, 오래전에 적재되었어도 여전히 자주 사용되는 페이지를 무작정 내보낼 위험이 있고, 프레임 수를 늘렸는데도 오히려 페이지 폴트가 증가하는 이례적인 현상이 나타날 수 있다는 한계가 알려져 있다.
이론적으로 가장 이상적인 방식은 앞으로 가장 오랫동안 사용되지 않을 페이지를 내보내는 최적 교체 방식이다. 이는 최저 수준의 페이지 폴트율을 보장하지만, 운영체제가 미래에 어떤 페이지가 참조될지 미리 알 수 없기 때문에 실제 시스템에는 적용할 수 없고, 다른 알고리즘의 성능을 평가하는 이론적 기준으로만 활용된다.
현실적인 대안으로 널리 쓰이는 방식은 가장 오랫동안 사용되지 않은 페이지를 내보내는 최소 최근 사용 방식이다. 이는 프로그램이 최근에 자주 참조한 데이터를 가까운 미래에도 다시 참조할 가능성이 높다는 참조 지역성의 경험적 원리에 근거하며, 최적 방식에 근접한 성능을 보이는 것으로 알려져 있어 현대 운영체제와 데이터베이스, 캐시 시스템 전반에서 표준적으로 채택되고 있다. 다만 각 페이지가 마지막으로 언제 사용되었는지를 정확히 기록하려면 별도의 하드웨어 지원이나 오버헤드가 수반된다.

▍ 내부 단편화와 외부 단편화의 차이
메모리 관리 방식을 비교할 때 자주 언급되는 개념이 단편화이다. 연속 메모리 할당 방식에서는 프로세스를 통째로 하나의 연속된 공간에 배치해야 하므로, 빈 공간들의 총합은 충분하더라도 조각조각 흩어져 있어 특정 크기 이상의 프로세스를 수용하지 못하는 외부 단편화 문제가 발생하기 쉽다. 이를 해소하려면 실행 중인 프로세스들을 한쪽으로 몰아 빈 공간을 압축하는 작업이 필요한데, 이 과정에서 시스템이 일시적으로 멈추는 부담이 따른다.
페이징은 프로세스를 일정한 크기의 조각으로 나누어 흩어진 프레임 어디에나 배치할 수 있도록 하기 때문에 외부 단편화 문제를 원천적으로 없앤다. 다만 이 방식에도 완전히 낭비가 없는 것은 아니다. 프로세스의 전체 크기가 페이지 크기의 정확한 배수가 아니라면, 마지막 페이지는 실제로 필요한 양보다 남는 여유 공간을 포함한 채 하나의 프레임 전체를 차지하게 된다. 이렇게 페이지 내부에서 발생하는 낭비를 내부 단편화라 부르며, 외부 단편화에 비해 그 규모는 훨씬 작지만 완전히 사라지지는 않는다.
결과적으로 페이지 크기를 어떻게 설정할지는 트레이드오프의 문제가 된다. 페이지 크기를 작게 잡으면 내부 단편화로 인한 낭비는 줄어들지만 페이지 테이블의 항목 수가 늘어나 관리 부담이 커지고, 반대로 페이지 크기를 크게 잡으면 페이지 테이블은 작아지지만 내부 단편화로 인한 낭비가 커질 수 있다. 서버나 고성능 컴퓨팅 환경에서는 상황에 따라 일반적인 크기보다 훨씬 큰 페이지를 지원하기도 하는데, 이는 TLB 미스를 줄이고 캐시 효율을 높이려는 목적에서 비롯된다.

▍ 페이지 테이블 구조의 확장과 계층적 관리
현대 시스템에서 사용되는 주소 공간은 매우 방대하기 때문에, 단일한 하나의 페이지 테이블만으로는 그 규모를 감당하기 어려운 경우가 많다. 페이지 크기가 작을수록, 그리고 주소 공간이 넓을수록 페이지 테이블 자체가 차지하는 메모리 용량도 함께 커지기 때문이다. 이 문제를 완화하기 위해 페이지 테이블 자체를 다시 페이징하는 계층적 페이징 기법이 사용되기도 한다.
계층적 구조에서는 논리 주소가 여러 단계의 페이지 번호와 최종 오프셋으로 구성되며, 바깥쪽 페이지 테이블을 거쳐 안쪽 페이지 테이블을 찾고, 그 안쪽 테이블에서 다시 실제 프레임 번호를 확인하는 다단계 탐색 과정을 거친다. 이 방식은 프로세스가 실제로 사용하지 않는 주소 영역에 대해서는 하위 페이지 테이블 자체를 만들지 않아도 되므로 전체적인 메모리 절약 효과가 있다. 다만 계층 단계가 늘어날수록 페이지 폴트 한 번을 처리하기 위해 거쳐야 하는 메모리 참조 횟수도 함께 늘어날 수 있다는 점은 성능 설계에서 함께 고려해야 할 요소이다.
▍ 가상 메모리와 페이징이 가지는 실제적 의미
가상 메모리와 페이징 기법이 결합됨으로써 얻어지는 이점은 단순히 메모리 용량을 확장하는 데 그치지 않는다. 각 프로세스가 독립적인 가상 주소 공간을 부여받기 때문에 서로 다른 프로세스가 같은 논리 주소를 사용하더라도 실제로는 전혀 다른 물리 메모리 영역에 매핑되어 충돌이 발생하지 않으며, 이는 곧 프로세스 간 격리를 통한 안정성과 보안성 향상으로 이어진다. 어떤 프로세스가 오작동을 일으키더라도 다른 프로세스나 운영체제 영역을 임의로 침범할 수 없도록 페이지 테이블의 권한 비트가 이를 통제한다.
또한 자식 프로세스를 생성하는 과정에서도 페이징 구조가 효율성을 높이는 데 활용된다. 부모 프로세스의 메모리 내용을 즉시 전부 복제하는 대신, 우선 페이지 테이블만 복사하여 부모와 자식이 동일한 물리 프레임을 함께 참조하도록 하고, 둘 중 하나가 실제로 데이터를 변경하려는 시점에 비로소 해당 페이지만 별도로 복제하는 쓰기 시 복사 방식이 널리 쓰인다. 이는 읽기 전용으로만 사용되는 코드 영역과 같은 공통 자원에 대해 불필요한 복제를 방지하여 프로세스 생성 속도와 메모리 효율을 동시에 끌어올린다.
물론 페이징에도 한계는 존재한다. 주소 변환 과정에서 페이지 테이블을 참조해야 하는 추가적인 부담이 있으며, 물리 메모리에 할당된 프레임 수가 프로세스가 실제로 필요로 하는 작업 집합에 비해 지나치게 적으면 페이지 교체가 끊임없이 반복되며 시스템이 실질적인 연산보다 메모리 입출력에 더 많은 시간을 쓰게 되는 스래싱 현상이 나타날 수 있다. 이 때문에 운영체제는 각 프로세스에 몇 개의 프레임을 배분할지를 정하는 프레임 할당 정책과, 실행 중인 프로세스의 작업 집합을 파악해 동적으로 프레임 수를 조정하는 기법을 함께 운용하며 안정적인 성능을 유지하려 한다.
▍ 마무리
가상 메모리와 페이징의 동작 원리를 정리하면, 프로세스의 논리 주소 공간과 물리 메모리를 동일한 크기의 페이지와 프레임으로 나누고, 페이지 테이블과 MMU를 통해 이 둘을 실시간으로 매핑함으로써 외부 단편화 문제를 해소하고 물리 메모리보다 큰 프로그램의 실행을 가능하게 하는 것이 핵심이다. TLB를 통한 변환 속도 개선, 요구 페이징을 통한 필요 시점의 페이지 적재, 그리고 다양한 페이지 교체 알고리즘을 통한 효율적인 프레임 관리가 서로 맞물려 오늘날의 컴퓨터 시스템이 제한된 물리 자원으로도 다수의 프로세스를 안정적으로 실행할 수 있도록 뒷받침하고 있다. 운영체제나 시스템 프로그래밍을 공부하는 과정에서 이러한 메모리 관리의 기본 원리를 정확히 이해해 두면, 프로그램의 성능 문제를 분석하거나 시스템 자원을 효율적으로 설계하는 데 실질적인 도움이 될 것이다.
'연예이슈' 카테고리의 다른 글
| 캐시 메모리가 시스템 성능에 미치는 영향과 작동 원리 (0) | 2026.07.17 |
|---|---|
| CPU 스케줄링 알고리즘 비교 분석: FIFO, SJF, Round Robin의 원리와 성능 특성 (1) | 2026.07.17 |
| 객체지향 프로그래밍(OOP)의 4대 특성과 실무 활용 완전 정리 (0) | 2026.07.16 |
| 리눅스 기본 명령어 20가지, 이것만 알면 서버 관리의 뼈대가 잡힌다 (0) | 2026.07.16 |
| Git과 GitHub의 차이, 그리고 첫 커밋까지: 5분 만에 이해하는 버전 관리의 핵심 원리 (0) | 2026.07.16 |