이 문서의 과거 버전 (r1)을 보고 있습니다. 수정일: 2026.02.13 22:23
운영체제의 메모리 관리는 컴퓨터 시스템의 핵심 자원인 주기억장치를 효율적으로 운영하고 할당하는 기능을 말한다. 이는 다중 프로그래밍 환경에서 여러 프로세스가 동시에 메모리에 상주하며 실행될 수 있도록 지원하며, 각 프로세스가 필요로 하는 메모리 공간을 안전하고 격리된 상태로 제공하는 것을 목표로 한다.
메모리 관리의 주요 역할은 메모리의 할당과 회수, 논리 주소와 물리 주소 간의 변환(주소 바인딩), 메모리 보호, 그리고 가상 메모리를 통한 메모리 공간의 확장이다. 특히 가상 메모리는 실제 물리 메모리 크기보다 훨씬 큰 논리적 주소 공간을 프로세스에 제공함으로써 대용량 프로그램의 실행을 가능하게 하고, 메모리 이용 효율을 극대화하는 핵심 기술이다.
이를 구현하기 위한 다양한 기법이 발전해왔으며, 대표적으로 연속 메모리 할당, 페이징, 세그먼테이션 등이 있다. 현대 운영체제는 대부분 페이징 기반의 가상 메모리 시스템을 채택하고 있으며, 페이지 교체 알고리즘과 TLB(변환 색인 버퍼) 같은 하드웨어 지원을 통해 성능을 최적화한다.
효율적인 메모리 관리는 시스템의 전반적인 성능과 안정성에 직접적인 영향을 미친다. 메모리 할당의 비효율은 외부 단편화나 내부 단편화를 유발하고, 잘못된 페이지 교체 정책은 스레싱 현상을 일으켜 시스템 성능을 급격히 저하시킬 수 있다. 따라서 운영체제는 이러한 문제들을 해결하기 위한 정교한 메커니즘을 지속적으로 발전시켜 왔다.
운영체제의 메모리 관리는 프로세스가 효율적이고 안전하게 주기억장치를 사용할 수 있도록 하는 핵심 기능이다. 이는 제한된 물리적 자원을 여러 프로세스가 공유하면서도 각 프로세스가 마치 독점적으로 메모리를 사용하는 것처럼 보이게 한다. 기본 개념은 물리 메모리와 논리 메모리의 분리, 이들 간의 변환인 주소 바인딩, 그리고 메모리 영역의 안전한 격리와 협력을 위한 메모리 보호 및 메모리 공유로 구성된다.
물리 메모리는 RAM과 같은 하드웨어적 실제 메모리 주소 공간을 의미한다. 반면, 각 프로세스가 인식하는 독자적인 주소 공간을 논리 메모리 또는 가상 주소 공간이라고 한다. 프로세스는 항상 논리 주소를 사용하여 명령과 데이터에 접근하며, 이 논리 주소를 물리 주소로 변환하는 작업이 필요하다. 이 변환 과정을 주소 바인딩이라고 하며, 시점에 따라 컴파일 타임 바인딩, 로드 타임 바인딩, 실행 시간 바인딩으로 구분된다. 현대 운영체제는 대부분 실행 시간 바인딩을 사용하여 프로세스 실행 중에도 메모리 내 위치를 유연하게 변경할 수 있도록 지원한다. 이때 메모리 관리 장치와 같은 하드웨어 지원이 필수적이다.
메모리 보호는 한 프로세스가 다른 프로세스의 메모리 영역이나 운영체제 영역을 침범하지 못하도록 막는机制이다. 일반적으로 베이스 레지스터와 한계 레지스터 쌍을 사용하여 각 프로세스가 할당받은 메모리 세그먼트의 시작 주소와 길이를 정의한다. 프로세스가 생성한 모든 논리 주소는 베이스 레지스터 값에 더해져 물리 주소로 변환되기 전에 한계 레지스터 값과 비교되어 유효성을 검사받는다[1]. 이를 통해 프로세스의 비정상적인 메모리 접근을 차단하고 시스템의 안정성을 보장한다.
한편, 메모리 공유는 여러 프로세스가 동일한 물리 메모리 영역을 공유하여 자원의 중복을 줄이고 프로세스 간 통신을 가능하게 한다. 예를 들어, 여러 프로세스가 동일한 시스템 라이브러리 코드를 사용할 때, 해당 코드의 사본을 물리 메모리에 하나만 적재하고 각 프로세스의 페이지 테이블이 동일한 프레임을 가리키도록 설정할 수 있다. 이는 메모리 사용 효율을 극대화한다. 보호와 공유는 상반된 개념처럼 보이지만, 운영체제는 접근 권한 비트 등을 통해 특정 메모리 영역에 대한 읽기, 쓰기, 실행 권한을 세밀하게 제어함으로써 두 목적을 동시에 달성한다.
물리 메모리는 컴퓨터 시스템에 실제로 설치된 RAM과 같은 하드웨어 메모리 장치를 가리킨다. 이는 운영체제와 응용 프로그램이 실행될 때 코드와 데이터를 적재하는 물리적인 저장 공간이다. 물리 메모리의 각 바이트는 고유한 물리 주소로 식별된다.
반면, 논리 메모리는 각 프로세스가 독립적으로 소유한다고 인식하는 메모리 공간이다. 프로세스가 생성될 때 운영체제는 0번지부터 시작하는 연속된 주소 공간인 논리 주소 공간을 할당한다. 이 공간 내의 주소를 논리 주소 또는 가상 주소라고 부른다. 논리 메모리는 물리 메모리와 독립적으로 존재하며, 그 크기는 시스템의 물리 메모리 크기를 초과할 수 있다.
운영체제의 메모리 관리 장치는 주소 변환이라는 과정을 통해 논리 주소를 물리 주소로 매핑한다. 이 변환은 메모리 관리 장치와 페이지 테이블 같은 자료 구조를 통해 투명하게 이루어진다. 이를 통해 각 프로세스는 자신만의 고립된 메모리 공간을 가지게 되며, 다른 프로세스의 메모리 영역을 침범할 수 없게 되어 메모리 보호가 가능해진다.
프로세스가 사용하는 논리 주소를 실제 물리 메모리의 물리 주소로 변환하는 과정을 주소 바인딩이라고 한다. 이 바인딩은 프로그램이 실행되는 시점에 따라 세 가지 방식으로 나뉜다.
바인딩 시기 | 방식 | 특징 |
|---|---|---|
컴파일 타임 바인딩 | 컴파일 시 물리 주소 결정 | 재배치 불가능, 메모리 위치 고정 |
로드 타임 바인딩 | 프로그램 메모리 적재 시 주소 결정 | 컴파일 타임보다 유연하지만 실행 중 이동 불가 |
실행 시간 바인딩 | 실행 중 주소 변환 |
컴파일 타임 바인딩은 프로그램이 컴파일될 때 물리 주소가 결정되는 방식이다. 이 경우 프로그램은 반드시 지정된 메모리 위치에 적재되어야 하며, 실행 중 다른 위치로 이동시킬 수 없다. 로드 타임 바인딩은 프로그램이 메모리에 적재되는 시점에 물리 주소가 결정된다. 컴파일러가 재배치 가능 코드를 생성하면, 로더가 적재 시 최종 주소를 계산하여 바인딩한다.
현대 대부분의 운영체제가 채택하는 실행 시간 바인딩은 프로그램 실행 중에도 주소 변환이 가능한 방식이다. 이는 메모리 관리 장치 하드웨어의 지원을 필요로 한다. CPU가 생성하는 모든 논리 주소는 실행 중 MMU에 의해 동적으로 물리 주소로 변환된다. 이 방식을 통해 프로세스는 실행 중에 물리 메모리 내에서 이동될 수 있으며, 이는 가상 메모리 시스템과 스와핑을 구현하는 데 필수적인 기반이 된다.
메모리 보호는 각 프로세스가 자신에게 할당된 메모리 영역만 접근하도록 제한하여, 다른 프로세스나 운영체제의 메모리를 함부로 읽거나 쓰지 못하게 하는 기능이다. 이는 시스템의 안정성과 보안을 유지하는 데 핵심적이다. 일반적으로 메모리 관리 장치(MMU)의 하드웨어 지원을 받아 구현되며, 프로세스가 허용되지 않은 메모리 주소에 접근하려고 하면 세그멘테이션 폴트나 페이지 폴트와 같은 예외를 발생시켜 접근을 차단한다.
메모리 보호를 위한 주요 메커니즘으로는 베이스 레지스터와 한계 레지스터의 쌍을 사용하는 방법이 있다. 베이스 레지스터는 프로세스의 물리 메모리 시작 주소를, 한계 레지스터는 프로세스의 최대 크기를 저장한다. 프로세스가 생성한 모든 논리 주소는 베이스 주소에 더해지기 전에 한계 값과 비교되어 유효성을 검사받는다. 이 외에도 페이지 테이블의 각 항목에 읽기/쓰기/실행 권한 비트를 두는 방식으로 보호를 구현하기도 한다.
반면, 메모리 공유는 여러 프로세스가 동일한 물리 메모리 영역을 공통으로 접근할 수 있게 하는 기능이다. 이는 시스템 자원을 효율적으로 활용하고 프로세스 간 통신(IPC)을 촉진한다. 주로 코드 공유와 데이터 공유 형태로 이루어진다. 예를 들어, 동일한 프로그램의 여러 인스턴스(예: 텍스트 편집기)를 실행할 때, 각 프로세스는 고유의 데이터 영역을 가지지만 읽기 전용인 실행 코드(텍스트 세그먼트)는 하나의 물리적 사본을 공유한다.
메모리 보호와 공유는 상충되는 개념처럼 보이지만, 운영체제는 이 둘을 조화롭게 구현한다. 공유 메모리 영역에 대해서도 접근 권한을 엄격히 제어하여, 허가된 프로세스만 특정 방식(읽기 전용 또는 읽기/쓰기)으로 접근할 수 있게 한다. 페이징 시스템에서는 여러 프로세스의 페이지 테이블 항목이 동일한 물리 프레임을 가리키도록 설정하여 공유를 구현하며, 이때 각 페이지 테이블 항목의 보호 비트를 통해 접근 제어를 수행한다.
연속 메모리 할당 방식은 프로세스가 실행을 위해 필요한 메모리 공간을 물리 메모리의 연속된 영역에 할당하는 전통적인 방법이다. 이 방식은 메모리를 몇 개의 분할로 나누어 각 분할에 하나의 프로세스를 적재하는 방식으로, 크게 고정 분할 할당과 가변 분할 할당으로 구분된다.
고정 분할 할당은 메모리를 운영체제가 초기에 고정된 크기의 여러 분할로 나누어 관리하는 방식이다. 각 분할에는 정확히 하나의 프로세스가 적재되며, 프로세스의 크기가 분할 크기보다 작으면 남는 공간이 발생한다. 이렇게 분할 내부에서 사용되지 않고 낭비되는 메모리를 내부 단편화라고 한다. 반면, 가변 분할 할당은 메모리를 초기에 분할하지 않고, 프로세스가 적재될 때 요구하는 정확한 크기만큼의 연속된 공간을 할당한다. 이 방식은 내부 단편화가 발생하지 않지만, 프로세스들이 메모리에 적재되고 종료되기를 반복하다 보면 작은 여유 공간들이 산발적으로 생겨나 새로운 프로세스를 할당하기 어려운 외부 단편화 문제가 발생한다.
외부 단편화를 완화하기 위한 방법으로 메모리 압축이 사용된다. 이는 분산된 여러 개의 작은 여유 공간을 하나의 큰 연속 공간으로 만들기 위해 적재된 모든 프로세스를 메모리의 한쪽 끝으로 이동시키는 작업이다. 그러나 이 작업은 상당한 오버헤드를 유발한다. 가변 분할 방식에서 여유 공간을 관리하고 새로운 프로세스를 배치하기 위한 전략에는 여러 가지가 있다.
할당 전략 | 설명 | 장단점 |
|---|---|---|
최초 적합 | 메모리의 시작부터 탐색하여 프로세스가 들어갈 수 있는 첫 번째 여유 공간에 할당 | 탐색 속도가 빠르지만, 앞부분에 작은 공간이 많이 생길 수 있음 |
최적 적합 | 모든 여유 공간을 탐색하여 프로세스 크기와 가장 비슷한 크기의 공간에 할당 | 외부 단편화를 최소화하지만, 모든 공간을 탐색해야 해서 오버헤드가 큼 |
최악 적합 | 가장 큰 여유 공간에 프로세스를 할당 | 큰 공간을 남기지 않아 큰 프로세스의 할당 실패 가능성을 낮춤 |
연속 메모리 할당 방식은 구현이 비교적 단순하지만, 외부 단편화와 메모리 활용도 저하라는 근본적인 문제를 안고 있다. 이러한 한계를 극복하기 위해 페이징 시스템과 같은 비연속 메모리 할당 기법이 발전하게 되었다.
고정 분할 할당은 운영체제가 물리 메모리를 미리 고정된 크기의 여러 구역(분할)으로 나누어 각 프로세스에 할당하는 방식이다. 초기 메모리 관리 기법 중 하나로, 메모리 공간이 분할의 개수만큼의 프로세스만 동시에 수용할 수 있다는 특징을 가진다.
각 분할은 일반적으로 크기가 서로 다르게 설정되어 다양한 크기의 프로세스를 수용할 수 있도록 설계된다. 프로세스가 실행되기 위해 메모리에 적재될 때, 자신의 크기보다 크거나 같은 빈 분할 중 하나에 할당된다. 이때 프로세스의 크기가 분할의 크기보다 작으면, 분할 내에 사용되지 않고 남는 공간이 발생하는데, 이를 내부 단편화라고 부른다.
이 방식의 장점은 구현이 비교적 단순하고, 메모리 할당 및 회수 오버헤드가 작다는 점이다. 그러나 분할의 크기와 개수가 고정되어 있어 큰 프로세스를 수용할 수 있는 충분한 크기의 빈 분할이 없으면, 그 프로세스는 실행되지 못한다. 또한 작은 프로세스가 큰 분할에 할당되면 내부 단편화로 인해 메모리 이용 효율이 떨어지는 문제가 발생한다.
장점 | 단점 |
|---|---|
구현이 단순함 | 내부 단편화 발생 |
할당/회수 오버헤드 낮음 | 큰 프로세스를 수용할 빈 분할이 없을 수 있음 |
동시 실행 프로세스 수가 분할 개수로 제한됨 |
이 방식은 다중 프로그래밍의 초기 형태인 멀티태스킹 시스템에서 주로 사용되었으나, 효율성 문제로 인해 이후 가변 분할 할당 방식으로 대체되는 경향을 보였다.
가변 분할 할당은 프로그램이 적재될 때마다 필요한 만큼의 메모리 공간을 연속적으로 할당하는 방식이다. 프로그램의 크기에 맞춰 메모리 공간을 분할하기 때문에 고정 분할 할당 방식에서 발생하는 내부 단편화 문제를 근본적으로 해결한다. 운영체제는 사용 가능한 메모리 공간을 하나의 큰 가용 공간 풀로 관리하며, 프로그램이 종료되면 그 공간을 다시 풀에 반환한다.
새로운 프로그램이 적재 요청을 하면, 운영체제는 가용 공간 풀에서 프로그램 크기 이상의 공간을 찾아 할당해야 한다. 이때 사용되는 주요 할당 알고리즘에는 최초 적합, 최적 적합, 최악 적합 등이 있다. 최초 적합은 가용 공간 리스트를 순차적으로 탐색하다가 가장 먼저 발견된 충분히 큰 공간을 할당한다. 최적 적합은 프로그램 크기와 가장 비슷한 크기의 가용 공간을 찾아 할당하며, 최악 적합은 가장 큰 가용 공간을 할당한다.
알고리즘 | 설명 | 장점 | 단점 |
|---|---|---|---|
최초 적합 | 첫 번째로 발견된 충분한 공간 할당 | 탐색 속도가 빠름 | 큰 가용 공간이 조각날 수 있음 |
최적 적합 | 요구 크기와 가장 비슷한 공간 할당 | 공간 활용 효율이 좋음 | 매우 작은 조각(외부 단편화)이 많이 발생할 수 있음 |
최악 적합 | 가장 큰 가용 공간을 할당 | 작은 조각 생성을 억제할 수 있음 | 큰 가용 공간이 빨리 소모될 수 있음 |
이 방식의 가장 큰 문제는 외부 단편화이다. 프로그램의 적재와 종료가 반복되면서 메모리 전체에는 사용 가능한 총 공간은 충분하지만, 그 공간들이 여러 작은 조각으로 분산되어 있어 큰 프로그램을 적재할 수 없는 상황이 발생한다. 외부 단편화를 해결하기 위해 메모리 압축 기법이 사용되기도 하지만, 이는 모든 실행 중인 프로그램을 재배치해야 하므로 시스템에 큰 오버헤드를 초래한다.
외부 단편화는 메모리 공간 내에 사용 가능한 총 여유 공간은 충분하지만, 그 공간들이 작고 분산되어 있어 새로운 프로세스의 연속적인 메모리 요구를 충족시키지 못하는 현상이다. 이는 주로 가변 분할 할당 방식에서 발생한다. 프로세스들이 종료되면서 메모리를 반환하면, 그 자리에 다양한 크기의 빈 공간(홀)이 생기게 된다. 시간이 지남에 따라 이 빈 공간들이 조각나고, 새로운 프로세스를 할당할 수 있을 만큼 충분히 큰 연속된 공간을 찾기 어려워진다. 외부 단편화를 해결하기 위한 방법으로는 압축(메모리에 있는 모든 프로세스를 한쪽으로 이동시켜 빈 공간을 하나로 합치는 방법)이 있지만, 실행 중인 모든 프로세스를 재배치해야 하므로 시스템에 큰 오버헤드를 초래한다는 단점이 있다.
반면, 내부 단편화는 프로세스에 실제로 필요한 양보다 더 큰 메모리 블록이 할당되어, 그 블록 내부에서 사용되지 않고 낭비되는 공간이 생기는 현상이다. 이는 주로 고정 분할 할당 방식이나 페이징 시스템에서 발생한다. 예를 들어, 운영체제가 4KB 크기의 페이지 또는 고정된 파티션을 사용하는 경우, 프로세스의 크기가 5KB라면 두 개의 페이지(8KB)가 할당되어 3KB의 공간이 낭비된다. 이 낭비된 공간은 해당 프로세스 내부에 존재하지만 사용할 수 없다. 내부 단편화는 할당의 기본 단위가 클수록 그 정도가 심해질 수 있다.
두 단편화의 주요 차이점은 낭비되는 공간의 위치와 발생 원인에 있다. 아래 표는 이를 비교하여 보여준다.
특징 | 외부 단편화 | 내부 단편화 |
|---|---|---|
발생 주 방식 | ||
낭비 공간 위치 | 할당된 프로세스들 *사이*의 빈 공간 | 할당된 메모리 블록 *내부*의 미사용 공간 |
해결/완화 기법 | 작은 할당 단위 사용, 세그먼테이션 고려 | |
메모리 총량 | 총 여유 공간은 충분하지만 연속적이지 않음 | 프로세스에 실제 필요 이상으로 할당됨 |
페이징 시스템은 외부 단편화 문제를 근본적으로 해결하지만, 대신 내부 단편화를 유발한다. 세그먼테이션 시스템은 논리적 단위로 메모리를 관리하여 내부 단편화를 줄일 수 있지만, 세그먼트 크기가 가변적이므로 외부 단편화가 발생할 수 있다. 현대 운영체제는 주로 페이징을 기반으로 하여 외부 단편화를 피하고, 내부 단편화는 페이지 크기를 적절히 조정(예: 4KB)함으로써 관리한다.
페이징 시스템은 연속 메모리 할당 방식에서 발생하는 외부 단편화 문제를 해결하기 위해 고안된 메모리 관리 기법이다. 이 방식은 프로세스의 논리 메모리 공간을 고정 크기의 블록인 페이지로 나누고, 물리 메모리를 동일한 크기의 프레임으로 나누어, 페이지를 빈 프레임에 비연속적으로 할당한다. 각 프로세스는 자신만의 페이지 테이블을 가지며, 이 테이블은 각 논리적 페이지가 저장된 물리적 프레임 번호를 매핑한다.
페이지 테이블의 구조는 시스템에 따라 다양하다. 가장 기본적인 형태는 선형 페이지 테이블로, 모든 페이지 항목을 연속된 배열에 저장한다. 그러나 주소 공간이 커질수록 테이블 크기가 방대해지는 단점이 있다. 이를 보완하기 위해 다단계 페이지 테이블이 사용된다. 다단계 페이지 테이블은 페이지 테이블 자체를 다시 페이지 단위로 나누어, 필요한 부분만 메모리에 유지함으로써 공간 효율성을 높인다. 반면, 역페이지 테이블은 시스템 전체에 하나의 테이블만 두고, 물리 프레임을 기준으로 어느 프로세스의 어떤 페이지가 할당되었는지를 기록한다.
주소 변환 과정에서 페이지 테이블에 대한 접근은 추가적인 메모리 참조를 필요로 하므로 성능 저하가 발생할 수 있다. 이 문제를 완화하기 위해 TLB(변환 색인 버퍼)라는 고속 캐시 메모리가 사용된다. TLB는 최근에 사용된 페이지 번호와 그에 대응하는 프레임 번호를 저장한다. 주소 변환 시 먼저 TLB를 검사하고(TLB 히트), 해당 매핑 정보가 있으면 페이지 테이블 접근 없이 즉시 물리 주소를 얻을 수 있다. 정보가 없을 경우(TLB 미스) 페이지 테이블을 참조한 후 그 결과를 TLB에 갱신한다.
구성 요소 | 설명 |
|---|---|
프로세스의 논리 주소 공간을 나눈 고정 크기 블록 | |
물리 메모리를 나눈, 페이지와 동일한 크기의 블록 | |
각 논리 페이지가 위치한 물리 프레임 번호를 매핑하는 테이블 | |
페이지 테이블의 일부 항목을 캐싱하여 주소 변환 속도를 높이는 고속 하드웨어 |
페이징 시스템은 메모리를 고정 크기 단위로 관리하여 외부 단편화를 근본적으로 제거하고, 가상 메모리 구현의 기반을 제공한다는 장점이 있다. 그러나 내부 단편화가 발생할 수 있으며, 페이지 테이블 관리에 따른 오버헤드와 TLB 미스 시의 성능 패널티가 존재한다.
페이징 시스템은 물리 메모리를 고정 크기의 블록으로 나누어 관리하는 기법이다. 이때, 물리 메모리를 나눈 각각의 고정 크기 블록을 프레임이라고 부른다. 반면, 프로세스의 논리 메모리 공간을 같은 크기로 나눈 블록을 페이지라고 한다. 페이지와 프레임의 크기는 일반적으로 동일하며, 4KB, 8KB, 16KB 등 시스템에 따라 정의된다.
페이지는 프로세스가 사용하는 연속적인 논리 주소 공간의 일부를 나타내지만, 실제로는 물리 메모리 상에서 연속적으로 위치할 필요가 없다. 각 페이지는 사용 가능한 어떤 프레임에도 할당될 수 있다. 이는 연속 메모리 할당 방식에서 발생하는 외부 단편화 문제를 해결하는 핵심 원리이다. 운영체제는 페이지 테이블이라는 자료 구조를 통해 각 페이지가 어느 프레임에 매핑되어 있는지 관리한다.
용어 | 설명 | 특징 |
|---|---|---|
페이지(Page) | 프로세스의 논리 주소 공간을 일정한 크기로 나눈 블록 | 논리적 단위, 연속적일 필요 없음 |
프레임(Frame) | 물리 메모리를 일정한 크기로 나눈 블록 | 물리적 단위, 페이지가 적재되는 실제 공간 |
페이지 테이블(Page Table) | 페이지 번호와 해당 페이지가 적재된 프레임 번호의 매핑 정보를 담은 테이블 | 각 프로세스마다 하나씩 존재 |
프로세스가 실행될 때, 필요한 페이지들이 사용 가능한 프레임들에 적재된다. 이 매핑 관계는 완전히 독립적이므로, 서로 다른 프로세스의 페이지들이 물리 메모리 내에서 흩어져 존재할 수 있다. 이 방식은 메모리 공간의 활용도를 높이고, 프로세스의 물리 메모리 할당을 유연하게 만든다.
페이지 테이블은 논리 주소 공간과 물리 주소 공간 간의 매핑 정보를 저장하는 자료 구조이다. 각 프로세스는 자신만의 독립적인 페이지 테이블을 가지며, 이는 CPU의 메모리 관리 장치(MMU)가 논리 주소를 물리 주소로 변환할 때 참조하는 핵심 요소이다. 페이지 테이블의 각 항목(페이지 테이블 엔트리, PTE)은 해당 페이지가 할당된 프레임의 물리 주소 번호와 함께 다양한 제어 및 상태 비트를 포함한다. 주요 상태 비트로는 페이지의 물리 메모리 존재 여부를 나타내는 유효 비트(Valid bit), 읽기/쓰기 권한을 제어하는 보호 비트(Protection bit), 페이지가 최근에 접근되었는지 여부를 나타내는 참조 비트(Reference bit), 페이지 내용이 변경되었는지 여부를 기록하는 변경 비트(Dirty bit) 등이 있다.
기본적인 선형 페이지 테이블 구조는 간단하지만 큰 주소 공간(예: 64비트 시스템)에서는 비효율적일 수 있다. 모든 가능한 페이지에 대한 엔트리를 연속적으로 저장하기 때문에 테이블 자체가 매우 커져 메모리 공간을 많이 차지하게 된다. 이를 해결하기 위해 여러 계층적 구조가 사용된다. 대표적으로 다단계 페이지 테이블(Multi-level Page Table)이 있으며, 이는 페이지 테이블을 트리 구조로 구성하여 실제로 사용되는 주소 공간 영역에 대해서만 페이지 테이블 공간을 할당함으로써 메모리 사용을 최적화한다. 예를 들어, 2단계 페이지 테이블은 외부 페이지 테이블(페이지 디렉터리)과 내부 페이지 테이블로 구성되어 논리 주소를 두 번의 조회를 통해 변환한다.
구조 | 설명 | 장점 | 단점 |
|---|---|---|---|
선형 페이지 테이블 | 모든 페이지 엔트리를 연속 배열로 저장 | 구현이 단순하고, 변환 속도가 빠름 | 주소 공간이 클수록 테이블 크기가 방대해짐 |
다단계 페이지 테이블 | 페이지 테이블을 트리 형태로 계층화 | 사용되지 않는 주소 공간에 대한 테이블 공간을 절약 | 주소 변환에 더 많은 메모리 접근이 필요할 수 있음 |
역페이지 테이블 | 시스템 전체에 하나의 테이블을 두고 물리 프레임 번호로 논리 주소를 검색 | 테이블 크기가 물리 메모리 크기에만 비례함 | 특정 프로세스의 페이지를 찾는 검색 오버헤드가 큼 |
이 외에도 해시 페이지 테이블(Hashed Page Table)이나 역페이지 테이블(Inverted Page Table) 같은 대안적 구조가 존재한다. 해시 페이지 테이블은 가상 페이지 번호를 해시하여 테이블 크기를 줄이고, 역페이지 테이블은 시스템 전체에 물리 프레임 수만큼의 엔트리만을 유지한다. 각 구조는 메모리 공간 효율성과 주소 변환 속도 사이의 트레이드오프를 가지며, 운영체제는 하드웨어 아키텍처와 지원 기능에 따라 적절한 페이지 테이블 구조를 선택하여 구현한다.
TLB(Translation Lookaside Buffer)는 페이징 시스템의 성능을 극적으로 향상시키기 위해 설계된 특수한 고속 캐시 하드웨어입니다. CPU가 가상 주소를 물리 주소로 변환할 때마다 메모리에 위치한 페이지 테이블을 참조해야 한다면, 이는 두 번의 메모리 접근(페이지 테이블 접근 후 실제 데이터 접근)을 유발하여 시스템 속도를 크게 저하시킵니다. TLB는 이러한 오버헤드를 줄이기 위해 최근에 사용된 가상 주소와 물리 주소의 매핑 정보를 저장합니다.
TLB의 동작 방식은 다음과 같습니다. CPU가 가상 주소를 생성하면, 하드웨어는 먼저 TLB를 검색합니다. 만약 해당 가상 페이지 번호에 대한 변환 정보가 TLB에 존재하면 이를 TLB 히트(TLB hit)라고 하며, 변환된 물리 프레임 번호를 즉시 얻어 매우 빠르게 메모리에 접근할 수 있습니다. 반대로 TLB에 해당 매핑이 없으면 TLB 미스(TLB miss)가 발생하며, 이때는 메모리에 있는 전체 페이지 테이블을 참조하여 주소 변환을 수행합니다. 이 과정에서 얻은 새로운 매핑 정보는 이후 참조를 위해 TLB에 로드됩니다.
TLB의 성능은 참조 지역성 원리에 크게 의존합니다. 일반적인 프로그램은 시간적 지역성(최근 접근한 주소를 다시 접근할 가능성)과 공간적 지역성(접근한 주소 근처의 주소를 접근할 가능성)을 가지므로, TLB는 높은 히트율을 보입니다. TLB의 구조는 완전 연관 매핑이나 집합 연관 매핑 방식을 사용하며, 크기는 일반적으로 64개에서 1024개 정도의 엔트리로 제한됩니다. TLB 미스 처리는 하드웨어(MMU)나 소프트웨어(운영체제)가 담당할 수 있습니다.
세그먼테이션 시스템은 프로그램을 논리적인 단위인 세그먼트로 나누어 메모리에 할당하는 방식이다. 각 세그먼트는 주어진 기능을 수행하는 코드의 모음, 데이터의 집합, 스택 영역 등과 같이 의미상 하나의 단위를 이룬다. 이 방식은 프로그램의 논리적 구조를 메모리 관리에 반영하여, 페이징 시스템이 물리적 메모리를 고정된 크기의 블록으로만 나누는 것과 대비된다.
각 세그먼트는 서로 다른 크기를 가지며, 독립적으로 메모리에 적재된다. 운영체제는 세그먼트 테이블을 사용하여 각 세그먼트의 관리 정보를 유지한다. 세그먼트 테이블의 각 항목은 일반적으로 세그먼트의 기준 주소(Base), 세그먼트의 길이(Limit), 그리고 접근 권한 정보를 포함한다. 논리 주소는 <세그먼트 번호, 오프셋>의 쌍으로 표현되며, 이는 세그먼트 번호로 테이블을 참조한 후 기준 주소에 오프셋을 더해 물리 주소로 변환된다. 이 과정에서 오프셋이 세그먼트 길이를 초과하는지 검사하여 메모리 보호를 제공한다.
특징 | 세그먼테이션 | 페이징 |
|---|---|---|
관점 | 사용자/논리적 관점 | 시스템/물리적 관점 |
단위 크기 | 가변 길이 | 고정 크기 |
분할 기준 | 프로그램의 논리적 구조 | 물리 메모리의 효율적 활용 |
주요 문제 | 외부 단편화 | 내부 단편화 |
공유/보호 | 세그먼트 단위로 용이 | 페이지 단위로 가능 |
세그먼테이션의 주요 장점은 논리적 구조를 반영한 보호와 공유가 용이하다는 점이다. 예를 들어, 코드 세그먼트는 읽기-실행만 허용하고, 데이터 세그먼트는 읽기-쓰기를 허용하는 식으로 접근 권한을 세밀하게 제어할 수 있다. 또한 여러 프로세스가 같은 코드 세그먼트를 공유하여 메모리 효율성을 높일 수 있다. 반면, 가변 크기 할당으로 인해 외부 단편화가 발생할 수 있으며, 이는 메모리 압축과 같은 추가적인 관리 오버헤드를 유발한다. 현대 범용 운영체제는 주로 페이징을 기반으로 하되, 세그먼테이션의 논리적 보호 개념을 일부 통합하는 방식을 사용한다.
세그먼트 테이블은 세그먼테이션 시스템에서 각 세그먼트의 물리 메모리 내 위치와 속성 정보를 관리하는 핵심 자료 구조이다. 각 프로세스는 자신의 세그먼트 테이블을 가지며, 이 테이블은 일반적으로 메모리 관리 장치(MMU)와 운영체제 커널에 의해 관리된다. 세그먼트 테이블의 각 항목은 하나의 세그먼트에 대한 정보를 담고 있으며, 이를 세그먼트 디스크립터라고 부른다.
주요 구성 요소는 다음과 같다.
항목 | 설명 |
|---|---|
기준 주소(Base Address) | 해당 세그먼트가 적재된 물리 메모리의 시작 주소를 나타낸다. |
한계 길이(Limit) | 세그먼트의 최대 길이를 바이트나 워드 단위로 지정한다. 이는 메모리 보호를 위한 범위 검사에 사용된다. |
보호 비트(Protection Bits) | 세그먼트에 대한 접근 권한(읽기, 쓰기, 실행)을 정의한다. |
존재 비트(Present Bit) | 해당 세그먼트가 현재 물리 메모리에 적재되어 있는지 여부를 나타낸다. |
논리 주소는 세그먼트 번호와 세그먼트 내 오프셋으로 구성된다. 메모리 관리 장치는 논리 주소의 세그먼트 번호를 인덱스로 사용하여 세그먼트 테이블에서 해당 디스크립터를 찾는다. 그 후 오프셋이 한계 길이보다 작은지 검사하여 세그먼테이션 오류(일반적으로 보호 오류)를 방지한다. 검사를 통과하면 기준 주소에 오프셋을 더해 최종 물리 주소를 계산한다.
세그먼트 테이블 자체도 메모리에 상주하므로, 이를 가리키는 세그먼트 테이블 기준 레지스터(STBR)가 필요하다. 이 레지스터는 현재 실행 중인 프로세스의 세그먼트 테이블 시작 주소를 저장한다. 세그먼테이션은 프로그램의 논리적 구조를 반영하여 메모리를 관리하므로, 공유와 보안 측면에서 유리하다. 예를 들어 코드 세그먼트는 여러 프로세스가 읽기 전용으로 공유할 수 있으며, 데이터 세그먼트는 독립적으로 보호될 수 있다.
페이징과 세그먼테이션은 모두 가상 메모리를 구현하여 물리 메모리의 제약을 극복하는 기법이다. 그러나 두 방식은 메모리를 나누는 단위와 관리 방식에서 근본적인 차이를 보인다. 페이징은 프로세스의 주소 공간을 고정된 크기의 블록인 페이지로 분할하고, 물리 메모리도 같은 크기의 프레임에 할당한다. 반면, 세그먼테이션은 프로세스를 논리적 의미 단위(예: 코드, 데이터, 스택)로 나눈 세그먼트를 기준으로 메모리를 관리한다. 각 세그먼트는 가변 길이를 가지며, 독립적인 보호와 공유 속성을 부여받을 수 있다.
두 방식의 주요 차이점은 다음과 같이 표로 정리할 수 있다.
구분 | 페이징 | 세그먼테이션 |
|---|---|---|
메모리 분할 단위 | 고정 크기(페이지) | 가변 크기(세그먼트) |
주소 공간 분할 기준 | 물리적(크기 기준) | 논리적(의미 기준) |
단편화 발생 유형 | 주로 내부 단편화 | 주로 외부 단편화 |
보호 및 공유 단위 | 페이지 단위(비효율적) | 세그먼트 단위(효율적) |
주소 변환 테이블 | 페이지 테이블(1개) | 세그먼트 테이블(세그먼트마다 1개) |
사용자 인지 여부 | 사용자에게 보이지 않음(시스템 관리) | 사용자/컴파일러가 인지함 |
페이징의 가장 큰 장점은 메모리 관리의 단순함과 외부 단편화가 발생하지 않는다는 점이다. 모든 페이지가 동일한 크기이므로 할당과 재배치가 용이하다. 단점은 내부 단편화가 발생할 수 있으며, 논리적 관계와 무관하게 메모리가 나뉘어 보호와 공유가 비효율적일 수 있다. 반면, 세그먼테이션은 논리적 구조를 반영하여 보호와 공유를 세밀하게 구현할 수 있고, 내부 단편화가 없다. 그러나 가변 길이 세그먼트의 할당과 해제가 반복되면 외부 단편화가 심각해져 압축 작업이 필요할 수 있다는 단점이 있다.
현대 운영체제는 두 방식의 장점을 결합한 세그먼트-페이징 혼용 방식을 주로 사용한다. 이 방식은 사용자에게는 세그먼테이션의 논리적 뷰를 제공하고, 시스템 내부에서는 각 세그먼트를 다시 페이지로 나누어 물리 메모리에 할당한다. 이를 통해 세그먼테이션의 논리적 관리와 보호 장점을 유지하면서, 페이징의 외부 단편화 해결 및 효율적인 물리 메모리 관리 이점을 동시에 얻는다.
가상 메모리는 물리 메모리의 크기 제한을 극복하고, 각 프로세스에게 매우 큰 연속적인 주소 공간을 제공하기 위한 기술이다. 이 기법은 주소 바인딩 과정에서 논리 주소를 물리 주소로 변환할 때, 해당 논리 주소에 대응하는 데이터가 물리 메모리에 없을 수도 있다는 점을 허용한다. 운영체제는 페이지 테이블에 각 페이지의 현재 위치(물리 메모리 또는 디스크)와 유효성을 기록하는 유효 비트를 관리하여 이를 구현한다. 이를 통해 실제 물리 메모리 용량보다 훨씬 큰 프로그램을 동시에 실행할 수 있게 되며, 프로그래머는 메모리 제약을 크게 의식하지 않고 개발할 수 있다.
가상 메모리의 핵심 구현 방식은 요구 페이징이다. 요구 페이징에서는 프로세스 실행에 필요한 모든 페이지를 처음부터 물리 메모리에 적재하지 않는다. 대신, 프로세스가 특정 페이지에 접근하려 할 때 해당 페이지가 메모리에 없는 경우, 이를 페이지 부재라고 인식하고 운영체제가 디스크에서 해당 페이지를 물리 메모리로 불러온다. 이때, 물리 메모리에 여유 공간이 없다면 기존의 어떤 페이지를 디스크로 내보낼지 결정해야 하며, 이를 위한 정책이 페이지 교체 알고리즘이다. 대표적인 알고리즘으로는 가장 오래전에 사용된 페이지를 교체하는 FIFO, 미래의 참조를 예측하여 가장 오랫동안 사용되지 않을 페이지를 교체하는 최적 교체 알고리즘, 과거의 참조 기록을 근거로 가장 오랫동안 사용되지 않은 페이지를 교체하는 LRU 등이 있다.
페이지 교체가 너무 빈번하게 발생하면 시스템의 대부분의 시간이 페이지를 스왑 인/아웃하는 데 소모되며, 실제 처리량은 급격히 떨어진다. 이러한 현상을 스레싱이라고 한다. 스레싱을 방지하기 위한 모델 중 하나가 작업 집합 모델이다. 이 모델은 프로세스가 일정 시간 동안 실제로 접근하는 페이지들의 집합인 작업 집합을 유지하고, 해당 작업 집합이 물리 메모리에 상주하도록 보장한다. 또 다른 접근법으로는 페이지 부재 빈도를 모니터링하여, 부재 빈도가 너무 높으면 프로세스에 더 많은 프레임을 할당하고, 너무 낮으면 프레임을 회수하는 동적 할당 기법이 사용된다.
가상 메모리 시스템에서 요구 페이징은 프로그램 실행에 필요한 페이지만을 물리 메모리에 적재하는 방식이다. 프로그램이 시작될 때 모든 페이지를 메모리에 올리는 대신, 초기에는 최소한의 페이지(예: 스택, 힙, 코드의 일부)만 로드하고, 실제로 접근이 발생하는 페이지를 필요할 때마다 적재한다. 이 접근 시도를 페이지 참조라고 하며, 참조된 페이지가 현재 물리 메모리에 없는 상황을 페이지 폴트라고 한다.
페이지 폴트가 발생하면 운영체제는 다음과 같은 순서로 처리한다. 먼저, 참조된 가상 주소의 유효성을 검사한다. 유효하지 않은 접근이면 프로그램을 중단시킨다. 유효한 접근이면, 운영체제는 디스크 입출력을 시작하여 필요한 페이지를 보조기억장치(보통 스왑 영역)에서 물리 메모리의 빈 프레임으로 읽어온다. 이때, 대기 중인 프로세스는 대기 상태로 전환된다. 페이지 읽기가 완료되면, 해당 페이지 테이블 항목을 갱신하여 프레임 번호와 유효 비트를 설정하고, 프로세스를 다시 준비 큐에 넣는다.
요구 페이징의 주요 이점은 물리 메모리 사용량을 크게 줄일 수 있다는 점이다. 이를 통해 더 많은 프로세스를 동시에 실행하거나, 더 큰 프로그램을 실행할 수 있다. 또한, 프로그램 시작 시 모든 코드와 데이터를 로드할 필요가 없으므로 초기 로딩 시간이 단축된다. 그러나 단점은 페이지 폴트 처리에 따른 오버헤드가 존재한다는 것이다. 빈번한 페이지 폴트는 시스템 성능을 심각하게 저하시킬 수 있으며, 이를 스레싱이라고 한다.
요구 페이징의 효율성을 높이기 위해 사전 페이징 기법이 사용되기도 한다. 사전 페이징은 요구 페이징과 반대로, 프로세스가 곧 사용할 것으로 예상되는 페이지를 페이지 폴트가 발생하기 전에 미리 메모리로 읽어오는 방식이다. 이는 참조의 공간 지역성을 활용하여, 연속된 페이지 접근 시 발생할 수 있는 여러 번의 페이지 폴트를 한 번의 입출력으로 해결하려는 목적을 가진다.
페이지 교체 알고리즘은 가상 메모리 시스템에서 요구 페이징이 발생할 때, 물리 메모리가 가득 찬 상태에서 새로운 페이지를 불러오기 위해 기존의 어떤 페이지를 스왑 영역으로 내보낼지 결정하는 규칙이다. 효율적인 알고리즘은 페이지 부재 빈도를 줄이고 시스템 전체 성능을 높이는 데 핵심적인 역할을 한다. 이상적인 알고리즘은 앞으로 가장 오랫동안 사용되지 않을 페이지를 교체하는 것이지만, 미래의 접근 패턴을 알 수 없으므로 다양한 근사 알고리즘이 사용된다.
주요 페이지 교체 알고리즘은 다음과 같다.
알고리즘 | 설명 | 특징 |
|---|---|---|
FIFO(First-In First-Out) | 가장 먼저 적재된 페이지를 교체한다. | 구현이 간단하지만, 자주 사용되는 페이지도 오래되었다는 이유만으로 교체될 수 있어 성능이 낮을 수 있다. 벨레이디의 모순 현상이 발생할 수 있다[3]. |
최적 교체(OPT, Optimal) | 앞으로 가장 오랫동안 사용되지 않을 페이지를 교체한다. | 미래 접근 정보를 필요로 하므로 실제 구현은 불가능하지만, 다른 알고리즘의 성능 비교 기준으로 사용된다. |
LRU(Least Recently Used) | 가장 오랫동안 사용되지 않은 페이지를 교체한다. | 과거의 접근 이력을 기반으로 하여 OPT에 근접한 좋은 성능을 보인다. 카운터나 스택 등을 이용해 구현하지만, 오버헤드가 크다는 단점이 있다. |
LFU(Least Frequently Used) | 참조 횟수가 가장 적은 페이지를 교체한다. | 장기적으로 자주 사용되지 않는 페이지를 대상으로 한다. 초기에 많이 사용된 후 더 이상 사용되지 않는 페이지가 메모리를 차지할 수 있다. |
클럭 알고리즘(NRU, Not Recently Used) | 참조 비트를 사용하는 근사 LRU 알고리즘이다. | 페이지마다 참조 비트를 두고, 이를 주기적으로 검사하며 교체 대상을 선정한다. 성능과 구현 복잡도의 균형이 좋아 실제 시스템에서 널리 사용된다. |
알고리즘 선택은 시스템의 워크로드 특성과 구현 오버헤드 사이의 절충을 고려해야 한다. 일반적으로 LRU나 클럭 알고리즘이 좋은 성능을 보이며, 윈도우나 리눅스와 같은 현대 운영체제는 클럭 알고리즘의 변형을 주로 채택한다. 알고리즘의 성능은 페이지 부재율로 측정되며, 이는 스레싱 발생 여부와 직결된다.
스레싱은 시스템이 실제 유용한 작업보다 페이지 교체에 과도하게 많은 시간을 소비하여 처리량이 급격히 떨어지는 현상을 가리킨다. 이는 다중 프로그래밍의 정도가 지나치게 높아져 실행 중인 프로세스 수가 많아질 때 발생한다. 각 프로세스가 필요로 하는 최소한의 프레임 수를 할당받지 못하면, 활발히 사용 중인 페이지들이 계속해서 디스크로 스왑 아웃되고 다시 스왑 인되는 상황이 반복된다. 결과적으로 CPU 이용률은 낮아지고, 디스크 입출력은 포화 상태에 이르며, 시스템 전체의 성능이 극도로 저하된다.
스레싱을 탐지하고 완화하기 위한 주요 모델로 작업 집합 모델이 제안되었다. 이 모델은 프로세스가 일정 시간 동안 실제로 접근하는 페이지들의 집합, 즉 작업 집합을 기반으로 한다. 작업 집합은 시간에 따라 변화하지만, 일반적으로 지역성 원리에 따라 짧은 시간 간격 내에는 안정적인 특성을 보인다. 운영체제는 각 프로세스의 작업 집합 크기를 모니터링하여, 해당 프로세스에 충분한 프레임을 할당할 수 있도록 한다. 만약 모든 프로세스의 작업 집합 크기의 합이 사용 가능한 총 물리 메모리 프레임 수를 초과하면, 스레싱이 발생할 가능성이 높아진다.
스레싱을 해결하는 일반적인 방법은 다중 프로그래밍 정도를 조절하는 것이다. 운영체제는 페이지 폴트 빈도를 모니터링하여 이를 기준으로 스레싱을 감지한다. 페이지 폴트율이 너무 높으면 새로운 프로세스를 메모리에 적재하지 않고, 일부 프로세스를 일시 중단시켜 메모리에서 제거함으로써 남은 프로세스들에게 충분한 프레임을 보장한다. 반대로 페이지 폴트율이 너무 낮으면 다중 프로그래밍 정도를 높여 시스템 자원의 활용도를 증가시킬 수 있다.
개념 | 설명 | 목적 |
|---|---|---|
스레싱 | 과도한 페이지 교체로 인한 시스템 성능 급락 현상 | 탐지 및 방지 대상 |
작업 집합 | 프로세스가 최근 일정 시간(Δ, 윈도우) 동안 접근한 페이지 집합 | 프로세스에 필요한 메모리 양 측정 |
페이지 폴트 빈도 | 단위 시간당 발생하는 페이지 폴트의 횟수 | 스레싱 감지 및 메모리 할당 조절의 기준 |
작업 집합 모델 외에도, 작업 집합 모델은 스레싱을 방지하기 위해 예측 모델을 사용하기도 한다. 프로세스의 과거 페이지 참조 패턴을 분석하여 향후 필요한 프레임 수를 예측하고, 그에 따라 메모리를 사전에 할당하는 방식이다. 이러한 기법들은 가상 메모리 시스템이 효율적으로 동작하도록 보장하는 데 핵심적인 역할을 한다.
캐싱은 자주 접근하는 데이터를 더 빠른 저장 장치(CPU 캐시, RAM)에 임시로 저장하여 전체적인 시스템 성능을 향상시키는 기법이다. 운영체제는 파일 시스템의 메타데이터나 자주 사용되는 디스크 블록을 페이지 캐시나 버퍼 캐시 형태로 메모리에 유지하여 디스크 접근 횟수를 줄인다. 이는 접근 시간의 차이가 큰 저장 장치 계층 간의 성능 격차를 완화하는 핵심 메커니즘이다.
버퍼링은 데이터를 한 장치에서 다른 장치로 전송할 때, 속도 차이나 타이밍 불일치를 조정하기 위해 사용되는 임시 저장 영역을 의미한다. 예를 들어, 디스크에 데이터를 기록할 때 입출력 버퍼에 먼저 모아두었다가 한꺼번에 전송하거나, 네트워크 패킷을 수신할 때 소켓 버퍼에 임시 저장하여 애플리케이션이 처리할 수 있을 때까지 보관한다. 이를 통해 생산자-소비자 문제를 해결하고 시스템 효율성을 높인다.
두 기법은 밀접하게 연관되어 있으며, 현대 운영체제에서는 통합되어 구현되는 경우가 많다. 예를 들어, 리눅스 커널은 파일 데이터와 메타데이터 캐싱을 위해 페이지 캐시를 사용하며, 이는 동시에 디스크 입출력 작업을 위한 버퍼 역할도 수행한다. 캐싱과 버퍼링의 효과는 참조 지역성 원리에 크게 의존한다. 자주 또는 최근에 사용된 데이터가 다시 사용될 가능성이 높다는 이 원리를 통해 캐시 히트율을 높이고 불필요한 입출력 오버헤드를 줄일 수 있다.
리눅스는 가상 메모리 관리를 위해 페이지 기반의 계층적 시스템을 사용한다. 핵심 구조는 페이지 캐시, 슬랩 할당자, 버디 시스템 등으로 구성된다. 페이지 캐시는 디스크의 파일 데이터를 메모리에 캐싱하여 입출력 성능을 높인다. 슬랩 할당자는 커널 객체 할당을 효율화하고, 버디 시스템은 물리적 페이지 프레임의 할당과 회수를 담당한다. 리눅스는 또한 요구 페이징과 페이지 아웃 데몬(kswapd)을 통해 메모리 부족 시 페이지를 디스크의 스왑 영역으로 이동시킨다.
마이크로소프트 윈도우의 가상 메모리 시스템은 가상 주소 공간 관리자와 페이지 파일을 중심으로 작동한다. 각 프로세스는 전용의 큰 가상 주소 공간(예: 64비트 시스템에서 128TB)을 가지며, 물리 메모리와 페이지 파일을 백업 저장소로 사용한다. 작업 관리자의 '커밋' 수치는 할당된 가상 메모리의 총량을 나타낸다. 윈도우는 요구 페이징과 클러스터링 기법을 사용하여 페이지 부재 시 인접한 페이지들을 함께 로드하여 성능을 최적화한다.
두 시스템은 메모리 압박 상황을 처리하는 방식에서 차이를 보인다. 리눅스는 사용 가능한 메모리가 일정 수준 이하로 떨어지면 kswapd 데몬이 활성화되어 페이지 회수를 시작한다. 반면, 윈도우는 메모리 관리자 구성 요소가 시스템 작업 집합과 프로세스 작업 집합을 모니터링하며, 필요 시 페이지 프리징이나 작업 집합 트리밍과 같은 기법을 적용한다. 최신 윈도우는 또한 메모리 압축 기술을 도입하여 스왑 발생 빈도를 줄인다.
리눅스 커널의 메모리 관리는 가상 메모리 시스템을 기반으로 하며, 복잡한 계층 구조와 다양한 최적화 기법을 포함한다. 핵심은 프로세스마다 독립적인 4GB(32비트 시스템 기준)의 가상 주소 공간을 제공하고, 이를 물리 메모리 및 스왑 영역에 매핑하는 것이다. 메모리 관리는 가상 메모리 관리자(VMM)가 담당하며, 페이지 단위로 관리된다.
주요 관리 체계로는 버디 시스템과 슬랩 할당자가 있다. 버디 시스템은 물리 메모리의 연속적인 페이지 프레임을 효율적으로 할당하고 회수하는 데 사용된다. 이는 외부 단편화를 줄이기 위해 설계되었다. 반면, 슬랩 할당자는 커널 내부에서 자주 생성되고 소멸되는 작은 객체(예: 프로세스 디스크립터)를 위한 캐시 메커니즘으로, 내부 단편화와 할당 속도를 최적화한다.
리눅스는 메모리 사용 효율을 높이기 위해 여러 정책을 구현한다. 요구 페이징을 통해 실제로 필요한 페이지만 물리 메모리에 적재하며, 페이지 캐시를 통해 파일 I/O 성능을 극대화한다. 또한, 사용 가능한 물리 메모리가 부족해지면 kswapd 데몬이 활성화되어 LRU 알고리즘에 근거한 페이지 교체를 수행하여 메모리를 확보한다. 이 과정에서 더티 페이지는 먼저 스왑 영역이나 저장 장치에 기록된다.
구성 요소/기법 | 주요 역할 |
|---|---|
물리 페이지 프레임의 할당 및 해제 관리 | |
커널 객체 할당을 위한 고속 캐시 | |
디스크 파일 데이터를 캐싱하여 I/O 성능 향상 | |
백그라운드에서 페이지 교체를 수행하는 데몬 | |
극심한 메모리 부족 시 프로세스를 강제 종료 |
메모리 압박이 심각한 수준에 도달하면 OOM Killer(Out-Of-Memory Killer)가 작동하여 시스템 전체의 안정성을 유지하기 위해 메모리를 많이 소비하는 프로세스를 선정해 강제로 종료한다. 이러한 다층적 관리 체계는 리눅스가 데스크톱부터 서버, 임베디드 시스템까지 다양한 환경에서 효율적으로 동작할 수 있는 기반을 제공한다.
윈도우 운영체제는 가상 메모리 관리를 위해 요구 페이징 방식을 기반으로 한 복합적인 시스템을 사용한다. 핵심은 각 프로세스에 4GB(32비트 시스템 기준)의 가상 주소 공간을 제공하는 것이다. 이 공간은 사용자 모드 영역(일반적으로 하위 2GB)과 커널 모드 영역(상위 2GB)으로 나뉜다. 실제 데이터는 물리 메모리(RAM) 또는 디스크의 페이징 파일(pagefile.sys)에 저장되며, 메모리 관리 장치(MMU)와 운영체제가 협력하여 가상 주소를 물리 주소로 변환한다.
주요 관리 구성 요소로는 워킹 셋 관리자(Working Set Manager)가 있다. 이는 주기적으로 각 프로세스의 활성 페이지 집합인 워킹 셋을 조정하여 물리 메모리 사용을 최적화한다. 사용 빈도가 낮은 페이지는 페이징 파일로 내보내고(페이지 아웃), 다시 필요할 때 불러온다(페이지 인). 또한 프로세스 관리자와 메모리 관리자는 가상 주소 공간의 할당 및 매핑을 담당한다. 캐시 관리자는 파일 시스템 데이터를 메모리에 캐싱하여 디스크 접근 성능을 향상시킨다.
윈도우는 다양한 페이지 교체 정책을 혼합 사용하며, FIFO나 LRU 같은 단일 알고리즘보다 상황에 따라 적응적으로 동작한다. 시스템은 스레싱을 방지하기 위해 페이지 부재 빈도를 모니터링하고, 필요 시 프로세스의 워킹 셋 크기를 동적으로 조정하거나 새로운 물리 메모리 할당을 제한한다. 관리 도구로는 작업 관리자의 '성능' 탭과 '세부 정보' 탭, 그리고 리소스 모니터(resmon.exe)와 성능 모니터(perfmon.exe)를 통해 페이징 파일 사용량, 커밋 메모리, 페이지 부재율 등을 실시간으로 확인할 수 있다.
성능 최적화 기법은 가상 메모리 시스템의 효율성을 높이고 스레싱을 방지하며 전체 시스템 성능을 개선하기 위한 다양한 방법을 포함한다. 주요 목표는 페이지 폴트 발생률을 낮추고 메모리 접근 시간을 단축하며, 입출력 오버헤드를 최소화하는 것이다.
페이지 프리페칭은 프로그램이 실제로 요청하기 전에 앞으로 필요할 것으로 예상되는 페이지를 미리 물리 메모리로 불러오는 기법이다. 공간 지역성의 원리를 활용하여, 접근한 페이지 주변의 페이지나 순차적 실행 흐름의 다음 페이지들을 미리 로드한다. 이는 페이지 폴트로 인한 대기 시간을 줄여 성능을 향상시킨다. 작업 집합 모델을 기반으로 한 요구 페이징과 결합되어 사용되기도 한다.
메모리 압축은 스왑 영역으로 페이지를 내보내는 대신, 물리 메모리 내에서 사용 중인 페이지들의 데이터를 압축하여 공간을 확보하는 기술이다. z스왑이나 z램과 같은 방식으로 구현된다. 이는 상대적으로 느린 디스크 입출력을 유발하는 스왑 작업보다 빠른 CPU 연산을 통해 메모리 공간을 관리하므로, 스레싱이 발생하는 상황에서 성능 저하를 완화하는 데 효과적이다.
다른 중요한 기법으로는 다음과 같은 것들이 있다.
* TLB 최적화: TLB 히트율을 높이기 위해 TLB 엔트리 수를 늘리거나, 다단계 페이지 테이블을 사용하며, TLB 슈퍼를 도입하는 방법이 있다.
* 페이지 크기 조정: 애플리케이션의 접근 패턴에 따라 거대 페이지를 사용하면 TLB 미스와 페이지 테이블 크기를 줄일 수 있다.
* 페이지 캐싱과 버퍼 캐싱: 자주 접근하는 파일 데이터를 페이지 캐시에, 디스크 블록을 버퍼 캐시에 유지하여 디스크 접근을 최소화한다.
* 메모리 할당자 최적화: 슬랩 할당자나 버디 시스템과 같은 효율적인 커널 메모리 할당 알고리즘을 사용하여 내부 단편화와 할당/해제 오버헤드를 줄인다.
이러한 기법들은 현대 운영체제에서 하드웨어 지원(예: MMU, TLB)과 소프트웨어 알고리즘을 결합하여 통합적으로 적용된다. 최적의 성능을 달성하기 위해서는 애플리케이션의 메모리 접근 패턴과 시스템의 자원 제약을 고려하여 적절한 기법들을 선택하고 조정해야 한다.