문서의 각 단락이 어느 리비전에서 마지막으로 수정되었는지 확인할 수 있습니다. 왼쪽의 정보 칩을 통해 작성자와 수정 시점을 파악하세요.

가상 메모리 관리 | |
이름 | 가상 메모리 관리 |
분류 | |
주요 목적 | |
핵심 개념 | |
주요 구성 요소 | |
관련 하드웨어 | |
기술 상세 | |
동작 방식 | |
주요 기법 | |
페이지 교체 알고리즘 예시 | |
장점 | |
단점/오버헤드 | |
페이지 폴트 처리 | |
쓰레싱 | 과도한 페이지 폴트로 시스템 성능이 급격히 저하되는 현상 |
공유 메모리 지원 | |
관련 보안 기법 | |
역사/발전 | |

가상 메모리 관리는 운영체제의 핵심 기능 중 하나로, 물리 메모리의 한계를 넘어서는 가상 주소 공간을 제공하고 이를 효율적으로 관리하는 기법을 총칭한다. 이는 프로세스가 실제 물리 메모리보다 훨씬 큰 주소 공간을 사용할 수 있게 하며, 동시에 실행되는 여러 프로세스 간의 메모리 분리와 보안을 보장한다.
가상 메모리 관리의 기본 아이디어는 메모리 관리 장치와 운영체제가 협력하여 프로세스가 사용하는 가상 주소를 실제 데이터가 저장된 물리 주소로 변환하는 것이다. 이 변환 과정은 일반적으로 페이징이나 세그멘테이션 방식을 통해 이루어진다. 주요 관리 대상은 페이지 테이블, TLB, 페이지 프레임 등이며, 운영체제는 페이지 교체 알고리즘을 통해 물리 메모리가 부족할 때 어떤 페이지를 디스크로 내보낼지 결정한다.
이 시스템의 도입으로 얻는 주요 이점은 다음과 같다.
이점 | 설명 |
|---|---|
주소 공간 분리 | 각 프로세스는 독립적인 가상 주소 공간을 가지며, 다른 프로세스의 메모리를 침범할 수 없다. |
메모리 효율성 증가 | 요구 페이징을 통해 실제 필요한 부분만 물리 메모리에 적재하여 공간을 절약한다. |
프로그래밍의 단순화 | 프로그래머는 연속된 큰 메모리 공간을 가정하고 코드를 작성할 수 있다. |
결과적으로, 가상 메모리 관리는 시스템의 안정성, 보안, 그리고 자원 활용 효율을 크게 향상시키는 기반 기술이다. 현대의 대부분의 범용 운영체제는 복잡한 가상 메모리 관리자를 포함하고 있다.

가상 메모리는 운영체제가 제공하는 핵심 기능 중 하나로, 각 프로세스에게 실제 물리 메모리의 크기와 상관없이 매우 큰 연속된 주소 공간을 사용할 수 있는 환상을 제공하는 메모리 관리 기법이다. 이는 메모리 관리 장치(MMU)라는 하드웨어 지원을 통해 논리 주소(가상 주소)를 물리 주소로 변환하는 과정을 투명하게 수행함으로써 가능해진다. 가상 메모리의 주요 목적은 프로그래밍의 편의성을 높이고, 메모리를 효율적으로 활용하며, 시스템의 안정성과 보안을 강화하는 데 있다.
가상 메모리의 첫 번째 필요성은 주소 공간의 분리와 보안 강화에서 찾을 수 있다. 각 프로세스는 자신만의 독립된 가상 주소 공간을 할당받는다. 이 공간은 운영체제 커널 영역과 사용자 프로세스 영역으로 구분되며, 프로세스는 오직 자신에게 할당된 사용자 영역의 주소만 참조할 수 있다. 한 프로세스가 다른 프로세스의 메모리 영역이나 운영체제의 핵심 영역을 직접 접근하는 것은 불가능하다. 이는 잘못된 메모리 접근으로 인한 시스템 충돌을 방지하고, 악의적인 프로세스가 다른 프로세스의 데이터를 조작하는 것을 근본적으로 차단하여 시스템 보안을 강화한다.
두 번째 필요성은 메모리 효율성과 프로그래밍 편의성의 향상에 있다. 프로그래머는 실제 시스템에 설치된 물리 메모리의 크기나 다른 프로세스의 메모리 사용 상황을 고려하지 않고, 마치 매우 큰 메모리가 있는 것처럼 프로그램을 설계하고 개발할 수 있다. 실제로는 물리 메모리보다 큰 프로그램도 실행이 가능한데, 이는 운영체제가 현재 필요하지 않은 부분을 보조기억장치(예: 하드 디스크의 스왑 영역)로 일시적으로 옮겨놓고, 필요할 때만 물리 메모리로 불러오는 방식으로 관리하기 때문이다. 또한, 동적 라이브러리와 같은 코드나 데이터를 여러 프로세스가 공유할 수 있게 하여 물리 메모리의 중복 적재를 피하고 전체적인 메모리 사용 효율을 높인다.
각 프로세스는 운영체제에 의해 할당된 독립적인 가상 주소 공간을 가진다. 이 공간은 일반적으로 프로세스가 사용할 수 있는 전체 주소 범위(예: 32비트 시스템에서는 0x00000000부터 0xFFFFFFFF)를 논리적으로 정의한다. 실제 물리 메모리는 이 가상 주소 공간과는 별개로 존재하며, 운영체제와 메모리 관리 장치(MMU)가 페이지 테이블을 통해 두 공간 간의 변환을 관리한다.
이러한 분리는 근본적인 보안과 안정성을 제공한다. 한 프로세스가 자신에게 할당된 가상 주소 공간 내에서 메모리를 참조할 때, 그 주소는 반드시 해당 프로세스의 페이지 테이블을 통해 물리 주소로 변환된다. 따라서 한 프로세스는 다른 프로세스의 가상 주소 공간에 직접 접근할 수 없다. 만약 프로세스 A가 프로세스 B의 데이터 영역을 가리키는 주소를 사용하려고 시도하더라도, 그 주소는 프로세스 A 자신의 페이지 테이블에 매핑되어 있지 않거나, 전혀 다른 물리 페이지를 가리키게 되어 데이터 침해가 발생하지 않는다.
주소 공간 분리는 잘못된 메모리 접근으로부터 시스템을 보호하는 역할도 한다. 프로세스가 허용되지 않은 가상 주소(예: 매핑되지 않은 주소나 커널 영역 주소)를 참조하려고 하면 MMU가 이를 감지하고 페이지 폴트나 세그멘테이션 폴트를 발생시킨다. 이 폴트는 운영체제의 예외 처리기로 전달되어, 해당 프로세스를 강제 종료시키는 등의 조치를 취할 수 있게 한다. 이는 하나의 프로세스가 버그나 악성 코드로 인해 시스템 전체나 다른 프로세스를 충돌시키는 것을 방지한다.
또한, 커널 공간은 일반적으로 모든 프로세스의 가상 주소 공간 상단에 위치하지만, 특수한 권한이 설정된 페이지 테이블 항목을 통해 보호된다. 사용자 모드에서 실행되는 프로세스는 이 커널 영역에 매핑된 페이지에 접근할 수 없도록 제한된다. 커널에 대한 모든 접근은 반드시 정의된 시스템 콜 인터페이스를 통해서만 이루어져야 하며, 이는 운영체제의 무결성과 안정성을 유지하는 데 필수적이다.
가상 메모리는 물리적 메모리 크기의 제약을 넘어서는 프로그램 실행을 가능하게 하여 메모리 효율성을 극대화한다. 프로그램 전체가 항상 물리 메모리에 상주할 필요가 없으며, 현재 실행에 필요한 부분만 메모리에 적재되고 나머지는 보조기억장치에 저장된다. 이를 통해 제한된 물리 메모리로 더 많은 프로세스를 동시에 실행하거나, 물리 메모리보다 큰 프로그램을 실행할 수 있다. 또한, 사용되지 않는 메모리 영역을 보조기억장치로 내보내어 물리 메모리 공간을 확보하는 스왑 아웃이 가능해진다.
프로그래밍의 편의성 측면에서 가상 메모리는 프로그래머에게 연속적이고 균일한 논리적 주소 공간을 제공한다. 프로그래머는 실제 데이터가 물리 메모리나 디스크의 어느 위치에 있는지 고려할 필요 없이, 0번지부터 시작하는 자신만의 주소 공간을 기준으로 코드를 작성하면 된다. 이는 메모리 관리의 복잡성을 애플리케이션 개발자로부터 운영체제로 완전히 이전시키는 효과가 있다.
또한, 동적 메모리 할당이 단순화된다. 프로그램 실행 중 추가 메모리가 필요할 때, 운영체제는 프로세스의 가상 주소 공간 내에서 연속된 빈 영역을 쉽게 할당할 수 있다. 이 할당된 가상 주소 영역이 실제로 물리 메모리에서 연속된 공간에 매핑될 필요는 없다. 이로 인해 발생할 수 있는 물리 메모리의 단편화 문제는 운영체제가 투명하게 처리한다.
효율성 측면 | 편의성 측면 |
|---|---|
물리 메모리보다 큰 프로그램 실행 가능 | 연속된 논리 주소 공간 제공 |
사용 중인 페이지만 메모리에 유지(요구 페이징) | 메모리 할당 및 관리의 복잡성 추상화 |
여러 프로세스 간 물리 메모리 공유 용이 | 동적 라이브러리 공유 및 메모리 매핑 지원 |
사용되지 않는 페이지를 디스크로 스왑 아웃 | 물리적 메모리 배치를 고려하지 않은 프로그래밍 가능 |

페이징 시스템은 가상 메모리를 구현하는 가장 일반적인 기법이다. 이 시스템에서는 프로세스의 가상 주소 공간을 고정 크기의 블록인 페이지로 나누고, 물리 메모리 역시 같은 크기의 블록인 프레임으로 나눈다. 운영체제는 각 프로세스마다 페이지 테이블을 유지하며, 이 테이블은 가상 페이지 번호를 해당 페이지가 적재된 물리 프레임 번호로 변환하는 매핑 정보를 담고 있다. 이 방식의 핵심 장점은 프로세스의 메모리가 물리적으로 연속될 필요가 없다는 점이다. 각 페이지는 사용 가능한 어떤 프레임에도 배치될 수 있으며, 이를 통해 외부 단편화 문제를 효과적으로 해결한다.
페이지 테이블의 기본 구조는 간단한 선형 테이블이다. 각 항목(페이지 테이블 엔트리)은 해당 페이지의 물리 프레임 번호와 함께 여러 제어 비트를 포함한다. 주요 제어 비트로는 페이지가 물리 메모리에 존재하는지 나타내는 유효 비트, 읽기/쓰기 권한을 제어하는 보호 비트, 페이지가 변경되었는지 추적하는 더티 비트, 그리고 페이지가 메모리에 올라온 후 접근되었는지 확인하는 참조 비트 등이 있다. 페이지 테이블은 프로세스별로 존재하며, 그 위치는 페이지 테이블 베이스 레지스터가 가리킨다.
페이지 테이블 엔트리 구성 요소 | 설명 |
|---|---|
물리 프레임 번호 | 해당 가상 페이지가 적재된 물리 메모리의 프레임 번호 |
유효 비트 | 페이지가 물리 메모리에 유효하게 존재하는지(1), 아니면 디스크에 있는지(0) 표시 |
보호 비트 | 페이지에 대한 읽기, 쓰기, 실행 권한을 지정 |
참조 비트 | 페이지가 최근에 접근(읽기/쓰기)되었는지 추적 (페이지 교체 알고리즘에 사용) |
더티 비트 | 페이지가 메모리에서 변경(쓰기)되었는지 표시 (페이지를 디스크에 내보낼 때 필요) |
선형 페이지 테이블의 단점은 크기가 커질 수 있다는 점이다. 예를 들어, 32비트 주소 공간에서 4KB 페이지를 사용하면 약 100만 개의 엔트리가 필요하다. 이를 해결하기 위해 다단계 페이지 테이블이 등장했다. 이 방식은 페이지 테이블 자체를 다시 페이지로 나누어, 사용되지 않는 주소 공간에 대한 중간 단계의 페이지 테이블을 생성하지 않음으로써 공간을 절약한다. 대표적으로 2단계 또는 3단계, 현대 64비트 시스템에서는 4단계 또는 5단계 페이지 테이블을 사용한다.
페이지 테이블 조회는 모든 메모리 접근에 필요하므로, 이 변환 과정을 가속화하지 않으면 성능 저하가 불가피하다. 이를 해결하기 위한 하드웨어 지원 장치가 TLB이다. TLB는 자주 사용되는 페이지 테이블 엔트리(가상 페이지 번호와 물리 프레임 번호의 쌍)를 캐싱하는 고속 연관 메모리이다. 메모리 접근 시 CPU는 먼저 TLB에서 변환 정보를 찾고(TLB 히트), 실패할 경우(TLB 미스)에만 전체 페이지 테이블을 참조한다. TLB 히트율은 가상 메모리 시스템의 전체 성능에 지대한 영향을 미친다.
페이지 테이블은 가상 주소를 물리 주소로 변환하기 위한 핵심 자료 구조이다. 각 프로세스는 자신만의 페이지 테이블을 가지며, 운영체제는 메모리 관리 장치(MMU)와 협력하여 이 변환을 수행한다. 페이지 테이블의 각 항목(페이지 테이블 엔트리(PTE))은 특정 가상 페이지에 대한 정보를 담고 있다.
일반적인 페이지 테이블 엔트리는 다음과 같은 정보를 포함한다.
필드 | 설명 |
|---|---|
물리 프레임 번호 | 해당 가상 페이지가 매핑된 실제 물리 메모리의 프레임 번호이다. |
유효 비트 | 해당 매핑이 유효한지(페이지가 물리 메모리에 적재되었는지) 여부를 나타낸다. |
보호 비트 | 페이지에 대한 접근 권한(읽기, 쓰기, 실행)을 지정한다. |
참조 비트 | 페이지가 최근에 접근되었는지 추적하여 페이지 교체 알고리즘에 사용된다. |
변경 비트 | 페이지가 메모리에 적재된 후 수정되었는지 여부를 나타낸다. 이 비트는 페이지를 교체할 때 디스크에 다시 써야 하는지 결정하는 데 사용된다. |
단순한 선형 페이지 테이블은 모든 가상 페이지에 대한 엔트리를 연속적으로 저장하지만, 주소 공간이 커질수록 테이블 자체의 크기가 방대해지는 문제가 있다. 이를 해결하기 위해 다단계 페이지 테이블 구조가 널리 사용된다. 다단계 페이지 테이블은 페이지 테이블을 트리 구조로 구성하여, 사용되지 않는 주소 공간 영역에 대한 중간 단계의 페이지 테이블을 생성하지 않음으로써 공간을 절약한다. 예를 들어, 2단계 페이지 테이블은 가상 주소를 페이지 디렉터리 인덱스와 페이지 테이블 인덱스로 나누어 사용한다.
페이지 테이블은 프로세스별로 존재하며, 그 물리적 주소는 프로세스 제어 블록(PCB)에 저장된다. 문맥 교환 시 새로운 프로세스의 페이지 테이블 기준 주소가 페이지 테이블 베이스 레지스터(PTBR)에 로드되어 주소 변환의 기준이 된다. 페이지 테이블 구조의 설계는 메모리 접근 속도, 공간 오버헤드, 관리 복잡도 사이의 절충을 요구한다.
TLB(Translation Lookaside Buffer)는 가상 주소를 물리 주소로 변환하는 속도를 높이기 위해 사용하는 고속 캐시 메모리이다. 페이지 테이블은 주 메모리에 상주하기 때문에, 모든 메모리 접근에 대해 페이지 테이블을 참조하면 두 번의 메모리 접근(페이지 테이블 접근과 실제 데이터 접근)이 필요해 성능 저하가 발생한다. TLB는 최근에 사용된 가상 페이지 번호와 그에 대응하는 물리 프레임 번호의 매핑 정보를 저장하여, 이 변환 과정을 가속화한다.
TLB의 동작은 다음과 같다. CPU가 가상 주소를 생성하면, 하드웨어는 먼저 TLB를 검색한다. 만약 해당 가상 페이지 번호에 대한 항목이 TLB에 존재하면 이를 TLB 히트(TLB hit)라고 하며, 변환된 물리 주소를 즉시 얻을 수 있다. 항목이 존재하지 않으면 TLB 미스(TLB miss)가 발생하며, 이때는 주 메모리에 있는 페이지 테이블을 검색하여 매핑 정보를 찾아야 한다. 찾은 매핑 정보는 이후 참조를 위해 TLB에 로드된다.
TLB의 설계는 성능에 중요한 영향을 미친다. 일반적으로 TLB는 완전 연관 또는 집합 연관 매핑 방식을 사용하며, 제한된 크기를 가진다. TLB의 효율성은 참조의 지역성(Locality of Reference) 원리에 크게 의존한다. 프로그램이 짧은 시간 동안 특정 메모리 영역을 집중적으로 접근하는 특성 때문에, TLB 히트율은 매우 높게 유지되는 경우가 많다. TLB 미스 발생 시 처리는 하드웨어(예: x86 아키텍처의 MMU) 또는 운영체제 소프트웨어(예: MIPS 아키텍처)가 담당할 수 있다.
특징 | 설명 |
|---|---|
목적 | 주소 변환 속도 향상 |
저장 정보 | |
위치 | |
히트 시 | 변환 지연 시간이 매우 짧음 |
미스 시 | 페이지 테이블 참조 필요, 성능 저하 발생 |
멀티태스킹 환경에서 문맥 교환(Context Switch)이 발생하면, 새로운 프로세스는 다른 가상 주소 공간을 사용하므로 기존 TLB 항목들은 무효화되어야 한다. 이를 해결하기 위해 일부 아키텍처는 TLB 항목에 ASID(Address Space Identifier) 태그를 추가하여, 서로 다른 프로세스의 변환 정보를 TLB에 동시에 유지할 수 있도록 지원한다.

페이지 교체 알고리즘은 주기억장치의 모든 페이지 프레임이 사용 중일 때, 새로운 페이지를 적재하기 위해 어떤 기존 페이지를 보조기억장치로 내보낼지 결정하는 규칙이다. 이 알고리즘의 선택은 페이지 폴트 발생 빈도와 시스템 전체 성능에 직접적인 영향을 미친다. 이상적인 알고리즘은 미래의 페이지 참조를 예측하여 가장 오랫동안 사용되지 않을 페이지를 교체하는 것이지만, 실제로는 미래 참조를 알 수 없으므로 과거의 참조 패턴을 기반으로 한 다양한 휴리스틱 방법이 사용된다.
대표적인 알고리즘으로는 FIFO(First-In First-Out), LRU(Least Recently Used), LFU(Least Frequently Used) 등이 있다. FIFO는 가장 먼저 적재된 페이지를 교체하는 단순한 방식이지만, 자주 사용되는 페이지라도 오래 적재되었다는 이유만으로 교체될 수 있는 벨레이디의 모순 현상이 발생할 수 있다. LRU는 가장 오랫동안 사용되지 않은 페이지를 교체하는 방식으로, 시간적 지역성의 원리를 활용하여 FIFO보다 일반적으로 더 좋은 성능을 보인다. LFU는 참조 횟수가 가장 적은 페이지를 교체한다.
알고리즘 | 설명 | 주요 특징 |
|---|---|---|
가장 먼저 적재된 페이지를 교체 | 구현이 단순하지만 성능이 떨어질 수 있음 | |
가장 오랫동안 참조되지 않은 페이지를 교체 | 시간적 지역성을 잘 반영하여 우수한 성능 | |
OPT(Optimal) | 미래에 가장 오랫동안 사용되지 않을 페이지를 교체 | 이상적인 알고리즘이나 구현 불가능(미래 참조 예측 필요) |
클럭 알고리즘(2차 기회) | 참조 비트를 사용하여 교체 대상을 순환 탐색 | LRU의 근사 알고리즘으로, 합리적인 성능과 구현 비용을 가짐 |
실제 시스템에서는 LRU의 정확한 구현이 상당한 오버헤드를 수반하기 때문에, 클럭 알고리즘과 같은 근사(approximation) 알고리즘이 널리 사용된다. 또한, 워킹 셋 모델은 프로세스가 일정 시간 동안 집중적으로 접근하는 페이지 집합을 유지하여, 이 집합에 속하지 않는 페이지를 우선 교체 대상으로 고려한다. 이는 스래싱을 방지하고 메모리 사용의 지역성을 유지하는 데 도움을 준다.
페이지 교체 알고리즘은 물리 메모리가 가득 찼을 때, 어떤 페이지를 스왑 영역으로 내보낼지 결정하는 정책이다. 알고리즘의 선택은 페이지 폴트 발생 빈도와 시스템 전체 성능에 직접적인 영향을 미친다. 주요 알고리즘으로는 FIFO, LRU, OPT가 있으며, 각각 다른 교체 원칙을 따른다.
알고리즘 | 원칙 | 장점 | 단점 |
|---|---|---|---|
FIFO (First-In First-Out) | 가장 먼저 적재된 페이지를 교체한다. | 구현이 단순하고 오버헤드가 적다. | 벨레이디의 모순 현상이 발생할 수 있어, 프레임 수를 늘려도 페이지 폴트가 증가하는 경우가 있다. |
LRU (Least Recently Used) | 가장 오랫동안 사용되지 않은 페이지를 교체한다. | 시간적 지역성의 원리를 잘 반영하여 일반적으로 FIFO보다 성능이 우수하다. | 각 페이지에 대한 접근 시간을 기록하거나 순서를 유지해야 하므로 구현 오버헤드가 크다. |
OPT (Optimal) | 앞으로 가장 오랫동안 사용되지 않을 페이지를 교체한다. | 미래 접근을 알고 있다는 가정 하에 가능한 최소의 페이지 폴트를 보장한다. | 실제로 미래 접근 패턴을 알 수 없어 구현이 불가능하며, 다른 알고리즘의 성능 비교 기준으로 사용된다. |
FIFO는 큐(Queue)를 이용해 구현한다. 새로운 페이지가 적재되면 큐의 끝에 추가되고, 교체가 필요할 때는 큐의 맨 앞에 있는 페이지를 제거한다. LRU는 접근 시간을 기록하는 카운터나 페이지를 스택으로 관리하는 방식으로 구현한다. 최근에 접근된 페이지는 스택의 상단으로 이동시켜 관리한다. OPT는 이상적인 알고리즘이므로, 실제 시스템에서는 LRU의 근사 알고리즘(예: 추가 참조 비트, 2차 기회 알고리즘)이나 워킹 셋 모델을 활용해 구현한다.
워킹 셋 모델은 페이지 교체 알고리즘의 한 종류로, 프로세스가 일정 시간 동안 실제로 접근하는 페이지들의 집합인 워킹 셋을 유지하여 스래싱을 방지하고 메모리 할당을 최적화하는 이론적 모델이다. 이 모델은 피터 데닝에 의해 1960년대 후반 제안되었다[1].
워킹 셋은 과거 시간 간격 Δ(델타) 동안 참조된 페이지들의 집합으로 정의된다. 운영체제는 각 프로세스의 워킹 셋 크기(WSS)를 주기적으로 추정한다. 시스템의 총 메모리 요구량(D)은 모든 실행 중인 프로세스의 워킹 셋 크기의 합이다. 만약 가용 물리 메모리 프레임 수(m)가 D보다 작으면, 하나 이상의 프로세스를 일시 중단(스왑 아웃)시켜 m ≥ D가 되도록 하여 스래싱을 방지한다.
개념 | 설명 |
|---|---|
시간 간격 Δ | 워킹 셋을 계산할 때 고려하는 과거 참조 기간. 너무 작으면 지역성을 포착하지 못하고, 너무 크면 불필요한 페이지를 포함하게 된다. |
워킹 셋 크기(WSS) | 프로세스가 Δ 시간 동안 필요로 하는 고유 페이지의 수. 프로세스의 지역성 변화를 반영한다. |
총 요구량(D) | D = Σ WSS_i. 시스템에 필요한 총 물리 메모리 프레임 수의 추정치이다. |
이 모델은 페이지 폴트 빈도 알고리즘과 밀접한 관련이 있다. 워킹 셋을 유지하는 것은 프로세스에 충분한 프레임을 할당하여 페이지 폴트율을 낮은 수준으로 유지하는 것을 목표로 한다. 현대 운영체제는 워킹 셋 모델의 개념을 바탕으로 메모리를 관리하며, 예를 들어 윈도우 NT 계열은 '메모리 관리자'가 각 프로세스의 워킹 셋을 추적하고 조정한다.

세그멘테이션은 가상 메모리를 논리적인 단위인 세그먼트로 나누어 관리하는 기법이다. 각 세그먼트는 프로그램의 구성 요소, 예를 들어 메인 함수, 서브루틴, 스택, 힙, 데이터 영역 등과 같은 논리적 단위에 대응된다. 이는 단순히 고정된 크기의 블록으로 나누는 페이징과는 개념적으로 차이가 있다.
세그멘테이션 시스템에서는 각 세그먼트의 크기가 가변적이다. 운영체제는 세그먼트 테이블을 사용하여 가상 주소를 물리 주소로 변환한다. 세그먼트 테이블의 각 항목은 세그먼트의 시작 물리 주소(베이스)와 세그먼트의 길이(리미트)를 저장한다. 가상 주소는 세그먼트 번호와 세그먼트 내 오프셋으로 구성되며, 변환 시 오프셋이 세그먼트 길이를 초과하지 않는지 검사하여 메모리 보호를 제공한다.
특성 | 페이징 | 세그멘테이션 |
|---|---|---|
단위 | 고정 크기의 페이지 | 가변 크기의 세그먼트 |
나누는 기준 | 물리적, 시스템 관점 | 논리적, 사용자/프로그램 관점 |
단편화 | 내부 단편화 발생 가능 | 외부 단편화 발생 가능 |
공유/보호 | 페이지 단위 (비교적 복잡) | 논리적 단위 (보다 직관적) |
순수한 세그멘테이션은 외부 단편화 문제를 야기할 수 있다. 이 문제를 해결하고 두 기법의 장점을 결합하기 위해 현대 운영체제는 세그멘테이션과 페이징을 혼용한다. 대표적인 방식은 세그멘테이션된 주소 공간을 다시 페이지로 나누는 것이다. 즉, 시스템은 먼저 세그먼트 테이블을 통해 세그먼트를 찾고, 그 후 해당 세그먼트 내의 페이지 테이블을 통해 최종 물리 주소를 찾는다. 이 방식은 인텔 x86 아키텍처의 보호 모드에서 사용되었으며, 논리적 보호와 효율적인 물리 메모리 관리를 모두 달성한다.
세그멘테이션 시스템에서 각 세그먼트의 물리 메모리 내 위치와 속성 정보를 관리하는 핵심 자료 구조이다. 운영체제는 각 프로세스마다 고유한 세그먼트 테이블을 유지하며, 이 테이블은 보통 메모리 관리 장치(MMU)가 논리 주소를 물리 주소로 변환할 때 참조한다.
세그먼트 테이블의 각 항목은 하나의 세그먼트에 대한 정보를 담고 있으며, 일반적으로 다음과 같은 필드로 구성된다.
필드 | 설명 |
|---|---|
베이스(Base) | 해당 세그먼트가 적재된 물리 메모리의 시작 주소이다. |
한계(Limit) | 세그먼트의 길이 또는 최대 오프셋을 지정한다. 이를 통해 오프셋이 세그먼트 크기를 초과하는지 검사하여 메모리 보호를 제공한다. |
접근 권한 | 읽기, 쓰기, 실행 등 해당 세그먼트에 대한 접근 권한 비트를 포함한다. |
주소 변환 과정은 다음과 같다. 프로세스가 생성한 논리 주소는 세그먼트 번호(s)와 세그먼트 내 오프셋(d)으로 구성된다. MMU는 세그먼트 번호를 인덱스로 사용하여 세그먼트 테이블에서 해당 항목을 찾는다. 이후 오프셋(d)이 항목의 한계(Limit) 값보다 작은지 검사하고, 유효하다면 베이스(Base) 주소에 오프셋을 더해 최종 물리 주소를 계산한다. 오프셋이 한계를 초과하거나 접근 권한이 위반되면 세그멘테이션 폴트(예: 일반 보호 오류)가 발생한다.
세그멘테이션은 논리적 단위로 메모리를 관리하여 공유와 보안에 유리하지만, 외부 단편화 문제를 야기할 수 있다. 또한, 세그먼트 테이블 자체는 물리 메모리에 상주해야 빠른 주소 변환이 가능하므로, 시스템은 모든 프로세스의 세그먼트 테이블을 위한 메모리 공간을 추가로 관리해야 한다.
세그멘테이션과 페이징은 각각 장단점을 가지고 있어, 현대 운영체제는 종종 두 방식을 혼합하여 사용한다. 이 혼합 방식은 일반적으로 세그멘테이션 페이징 또는 페이징된 세그멘테이션으로 불린다.
이 방식은 먼저 프로세스의 논리 주소를 세그먼트 번호와 세그먼트 내 오프셋으로 나눈다. 이후 각 세그먼트는 고정 크기의 페이지들로 다시 분할된다. 시스템은 세그먼트 테이블을 통해 세그먼트의 시작 주소와 길이를 확인하고, 각 세그먼트는 자신의 페이지 테이블을 가진다. 최종적으로 페이지 테이블을 통해 오프셋을 페이지 번호와 페이지 내 변위로 변환하여 물리 주소를 얻는다.
아래 표는 두 방식의 주요 특징을 비교한다.
특성 | 세그멘테이션 | 페이징 |
|---|---|---|
주소 공간 분할 단위 | 논리적 의미(함수, 데이터)를 가진 가변 크기 세그먼트 | 고정 크기의 페이지 |
외부 단편화 | 발생함 | 발생하지 않음 |
내부 단편화 | 거의 발생하지 않음 | 발생할 수 있음 |
메모리 보호/공유 | 세그먼트 단위로 용이함 | 페이지 단위로 가능하나 의미론적이지 않음 |
주소 변환 복잡도 | 비교적 단순 | 다중 단계 테이블로 인해 더 복잡할 수 있음 |
혼합 방식은 세그먼테이션의 논리적 보호 및 공유 장점과 페이징의 물리 메모리 효율성 장점을 결합한다. 예를 들어, 코드 세그먼트와 데이터 세그먼트를 분리하여 각기 다른 보호 권한(읽기 전용, 읽기/쓰기)을 부여하는 동시에, 각 세그먼트 내부는 페이지로 관리되어 외부 단편화 문제를 해결한다. 그러나 이는 주소 변환에 세그먼트 테이블과 페이지 테이블을 모두 참조해야 하므로 오버헤드가 증가할 수 있다. 많은 현대 시스템은 단순화와 성능을 위해 하드웨어 수준에서 순수 페이징을 선호하지만, IA-32 아키텍처와 같은 일부 시스템은 여전히 혼합 방식을 일부 활용한다.

요구 페이징은 가상 메모리 시스템에서 프로그램 실행에 필요한 페이지를 실제 물리 메모리에 적재하는 방식이다. 이 방식은 프로그램 시작 시 모든 페이지를 메모리에 로드하지 않고, 실제로 접근이 발생할 때 해당 페이지를 메모리로 불러온다. 이는 초기 프로그램 로딩 시간을 단축시키고, 사용되지 않을 수도 있는 코드나 데이터를 미리 적재함으로써 발생하는 메모리 낭비를 방지한다.
요구 페이징의 핵심 동작은 페이지 폴트 처리 과정이다. 프로세스가 아직 물리 메모리에 없는 페이지에 접근하려고 하면 MMU가 이를 감지하고 페이지 폴트 예외를 발생시킨다. 운영체제의 페이지 폴트 핸들러는 다음과 같은 순서로 이 상황을 처리한다.
1. 접근한 가상 주소가 프로세스의 유효한 주소 공간인지 확인한다. 유효하지 않으면 세그멘테이션 폴트를 발생시킨다.
2. 요청된 페이지가 스왑 영역이나 디스크의 페이지 파일에 존재하는지 확인한다.
3. 물리 메모리에서 빈 프레임을 할당받는다. 만약 빈 프레임이 없다면 페이지 교체 알고리즘을 통해 희생될 프레임을 선택하고, 그 내용을 필요하다면 디스크에 기록한다.
4. 필요한 페이지를 디스크에서 빈 프레임으로 읽어온다.
5. 해당 프로세스의 페이지 테이블을 갱신하여 새로운 물리 프레임과의 매핑을 설정하고, 접근 권한을 설정한다.
6. 페이지 폴트를 발생시킨 명령어부터 프로세스 실행을 재개한다.
페이지 폴트 처리 시간은 디스크 입출력이 포함되기 때문에 상당히 길다. 이를 완화하기 위해 페이지 프리페칭 기법이 사용된다. 페이지 프리페칭은 프로세스가 향후 필요로 할 것으로 예상되는 페이지를 페이지 폴트가 발생하기 전에 미리 메모리로 적재하는 방법이다. 예측은 공간 지역성과 시간 지역성 원리를 바탕으로 이루어진다. 일반적인 전략으로는, 한 페이지에 폴트가 발생했을 때 인접한 몇 개의 페이지를 함께 적재하는 클러스터링이나, 프로세스의 과거 페이지 접근 패턴을 분석하여 예측하는 방법 등이 있다. 그러나 부정확한 예측은 불필요한 입출력과 메모리 낭비를 초래할 수 있다.
페이지 폴트는 프로세스가 접근하려는 가상 주소에 해당하는 페이지가 현재 물리 메모리에 로드되어 있지 않을 때 발생하는 예외 상황이다. 운영체제의 페이지 폴트 핸들러는 이 예외를 처리하여 필요한 페이지를 보조 기억 장치(예: 하드 디스크나 SSD)에서 물리 메모리로 불러온다.
페이지 폴트 처리 과정은 다음과 같은 단계로 진행된다.
1. 예외 탐지: MMU(메모리 관리 장치)가 페이지 테이블 항목의 유효 비트를 확인하여 페이지가 메모리에 없음을 감지하고, 운영체제 커널에 페이지 폴트 예외를 발생시킨다.
2. 주소 확인 및 권한 검사: 운영체제는 폴트를 일으킨 가상 주소와 접근 유형(읽기/쓰기)을 확인한다. 접근이 해당 메모리 영역의 권한(읽기 전용, 읽기/쓰기 등)을 위반한 경우 프로세스에 세그멘테이션 폴트(일반적으로 SIGSEGV 신호)를 보내 종료시킨다.
3. 물리 메모리 공간 확보: 접근이 유효한 경우, 운영체제는 빈 페이지 프레임을 찾는다. 사용 가능한 프레임이 없으면 페이지 교체 알고리즘을 실행하여 기존 페이지 하나를 선택해 보조 기억장치로 내보낸다.
4. 페이지 불러오기: 필요한 페이지의 데이터를 보조 기억장치(예: 스왑 영역 또는 파일 시스템)에서 빈 페이지 프레임으로 읽어온다. 이 과정은 상대적으로 느린 입출력 작업이다.
5. 페이지 테이블 갱신: 새로 로드된 페이지의 물리 주소와 유효 비트를 페이지 테이블에 기록한다. 필요에 따라 TLB 항목도 무효화한다.
6. 프로세스 재개: 페이지 폴트를 일으킨 명령어부터 프로세스의 실행을 다시 시작한다. 이제 해당 가상 주소에 대한 접근은 정상적으로 이루어진다.
페이지 폴트 처리에는 상당한 오버헤드가 수반된다. 특히 디스크 입출력이 포함되면 처리 시간이 수 밀리초 이상 걸릴 수 있다[2]. 따라서 페이지 폴트 발생 빈도는 시스템 전체 성능에 큰 영향을 미친다. 운영체제는 요구 페이징과 페이지 프리페칭 기법을 통해 페이지 폴트의 횟수와 그에 따른 성능 저하를 최소화하려고 한다.
페이지 프리페칭은 요구 페이징 시스템의 성능을 개선하기 위해, 실제 페이지 폴트가 발생하기 전에 미래에 필요할 것으로 예상되는 페이지를 사전에 물리 메모리로 불러오는 기법이다. 순수한 요구 페이징은 페이지가 참조될 때마다 폴트가 발생할 수 있어 입출력 오버헤드가 크다. 페이지 프리페칭은 이러한 오버헤드를 줄이고 프로그램의 실행 속도를 높이는 데 목적이 있다.
프리페칭의 효과는 참조의 지역성 원리에 기반한다. 프로그램은 일반적으로 순차적 실행이나 순환 구조를 가지므로, 특정 페이지가 참조되면 그 인접한 페이지들도 가까운 미래에 참조될 가능성이 높다. 따라서, 한 페이지가 폴트를 일으켜 메모리로 적재될 때, 그 주변의 몇 페이지를 함께 적재하는 방식이 흔히 사용된다. 이는 공간 지역성을 활용한 것이다.
프리페칭 정책은 크게 두 가지로 나뉜다. 하나는 고정된 개수의 인접 페이지를 미리 읽어오는 정적 방법이고, 다른 하나는 프로그램의 과거 페이지 참조 패턴을 분석하여 동적으로 프리페칭할 페이지를 결정하는 방법이다. 동적 방법은 더 정교하지만 구현 복잡도와 런타임 오버헤드가 따른다. 과도한 프리페칭은 사용되지 않을 페이지를 불러와 메모리 공간을 낭비하고 불필요한 입출력 경쟁을 유발할 수 있다.
프리페칭 유형 | 설명 | 장점 | 단점 |
|---|---|---|---|
클러스터링 | 페이지 폴트 발생 시, 해당 페이지뿐만 아니라 인접한 여러 페이지를 한 번에 디스크에서 읽어옴 | 구현이 간단하며, 순차적 접근 패턴에서 효과적 | 무작위 접근 패턴에서는 메모리 낭비 유발 |
실행 추적 기반 | 프로그램 실행 흐름을 모니터링하여 예측 모델을 통해 프리페칭 대상 결정 | 접근 패턴에 맞춘 정교한 예측 가능 | 런타임 모니터링 오버헤드와 예측 알고리즘 복잡도 존재 |
효과적인 페이지 프리페칭은 페이지 폴트율을 현저히 낮추고 전체 시스템 처리량을 향상시킨다. 그러나 프리페칭의 정확도와 적절한 프리페치 양을 결정하는 것은 중요한 설계 과제이다. 현대 운영체제와 CPU는 하드웨어 수준의 프리페처를 내장하여 캐시 라인을 미리 읽어오는 방식으로 이 개념을 확장 적용하기도 한다.

가상 메모리 시스템은 각 프로세스에 독립적인 주소 공간을 제공함으로써 메모리 보호와 공유를 구현하는 핵심 메커니즘이다. 운영체제는 페이지 테이블 또는 세그먼트 테이블 내에 접근 권한 비트를 설정하여 메모리 영역에 대한 읽기, 쓰기, 실행 권한을 제어한다. 이를 통해 사용자 프로세스가 다른 프로세스의 메모리나 운영체제 커널 영역을 함부로 접근하는 것을 방지한다. 예를 들어, 코드 영역은 일반적으로 읽기와 실행만 허용하고 쓰기는 금지하여 프로그램 코드가 실행 중에 변경되는 것을 막는다.
메모리 공유는 동일한 물리 메모리 페이지를 여러 프로세스의 가상 주소 공간에 매핑함으로써 이루어진다. 이는 주로 공유 라이브러리(공유 오브젝트)나 공통 데이터를 처리할 때 효율성을 높인다. 모든 프로세스가 동일한 물리 페이지를 참조하면 메모리 사용량이 줄어들고, 코드와 데이터의 일관성을 유지할 수 있다. 공유 페이지는 보통 읽기 전용으로 설정되거나, 쓰기 작업이 필요할 경우 쓰기 시 복사 기법과 함께 사용된다.
쓰기 시 복사는 메모리 공유의 한 형태로, 초기에는 여러 프로세스(예: fork 시스템 호출 후의 부모와 자식 프로세스)가 동일한 물리 페이지를 공유하다가, 어느 한 프로세스가 해당 페이지에 쓰기 작업을 시도할 때 비로소 그 프로세스를 위한 새로운 사본 페이지를 생성하는 기법이다. 이는 불필요한 메모리 복사를 최소화하면서 프로세스 간의 격리를 유지한다. 이 기법은 프로세스 생성 시간을 단축하고 메모리 사용량을 절약하는 데 크게 기여한다.
보호/공유 메커니즘 | 주요 목적 | 구현 방식 |
|---|---|---|
접근 권한 비트 | 무단 접근 방지 | 페이지/세그먼트 테이블 엔트리에 R(읽기), W(쓰기), X(실행) 플래그 설정 |
메모리 공유 | 효율성 및 일관성 | 여러 가상 주소를 하나의 물리 프레임에 매핑 |
쓰기 시 복사 | 초기 메모리 절약 및 격리 유지 | 쓰기 접근 발생 시 새 물리 프레임 할당 및 내용 복사 |
가상 메모리 시스템에서 접근 권한 비트는 각 페이지 또는 세그먼트에 대한 접근 권한을 정의하는 페이지 테이블 또는 세그먼트 테이블 항목 내의 특수한 비트 필드이다. 이 비트들은 운영체제가 메모리 보호를 구현하는 핵심 메커니즘으로 작동하여, 사용자 프로그램이 허가되지 않은 방식으로 메모리에 접근하는 것을 방지한다.
일반적인 접근 권한 비트는 읽기(Read), 쓰기(Write), 실행(Execute) 권한을 나타낸다. 예를 들어, 코드가 저장된 페이지는 읽기 및 실행 권한만 부여되고 쓰기 권한은 제거될 수 있다. 이는 프로그램 코드가 실행 중에 의도치 않게 변경되는 것을 막는다. 반면, 데이터 페이지는 읽기와 쓰기 권한을 가지지만 실행 권한은 가지지 않을 수 있다. MMU는 CPU가 메모리에 접근할 때마다 해당 가상 주소가 속한 페이지의 권한 비트를 검사한다. 프로그램이 현재 권한을 위반하는 작업(예: 쓰기 금지된 페이지에 데이터 쓰기)을 시도하면 MMU는 하드웨어 예외를 발생시키고, 운영체제는 이를 세그먼테이션 폴트 또는 보호 위반으로 처리하여 해당 프로세스를 종료시킨다.
권한 비트 | 설명 | 일반적인 용도 |
|---|---|---|
읽기(R) | 페이지의 내용을 읽을 수 있다. | 코드, 데이터, 읽기 전용 데이터 |
쓰기(W) | 페이지의 내용을 변경할 수 있다. | 스택, 힙, 전역 변수 데이터 |
실행(X) | 페이지의 내용을 기계어 명령어로 실행할 수 있다. | 프로그램 코드(.text 섹션) |
또한, 접근 권한 비트는 사용자 모드와 커널 모드(또는 슈퍼바이저 모드)를 구분하는 비트를 포함하기도 한다. 이 비트가 설정된 페이지는 운영체제 커널의 코드와 데이터를 저장하며, CPU가 특권 모드에서 실행 중일 때만 접근이 허용된다. 이를 통해 사용자 프로그램이 커널 메모리 영역을 직접 읽거나 수정하는 것을 차단하여 시스템의 안정성과 보안을 유지한다.
쓰기 시 복사는 메모리 관리 기법 중 하나로, 여러 프로세스가 동일한 데이터의 복사본을 필요로 할 때 초기에는 물리 메모리 상의 동일한 페이지를 공유하다가, 프로세스 중 하나가 해당 데이터에 쓰기 연산을 수행할 때 비로소 새로운 사본을 생성하는 방식이다. 이 기법은 메모리 사용량을 줄이고 시스템 성능을 향상시키는 데 기여한다.
주로 fork 시스템 호출과 같은 프로세스 생성 과정에서 활용된다. 부모 프로세스가 fork를 호출하여 자식 프로세스를 생성하면, 운영체제는 초기에는 자식 프로세스에게 부모의 전체 주소 공간을 복사하는 대신, 두 프로세스가 동일한 물리적 페이지 프레임을 읽기 전용으로 공유하도록 매핑한다. 이후 어느 한 프로세스가 공유된 페이지에 쓰기를 시도하면, 페이지 폴트가 발생하고 운영체제는 이때 비로소 해당 페이지의 새로운 사본을 만들어 요청한 프로세스에게 할당한다. 이로 인해 불필요한 메모리 복사 오버헤드를 피할 수 있다.
쓰기 시 복사의 주요 이점은 명백한 메모리 절약이다. 많은 유닉스 계열 운영체제에서 새 프로세스 생성 후 즉시 exec 시스템 호출을 실행하여 다른 프로그램을 로드하는 경우가 빈번하다. 이 경우 자식 프로세스는 부모의 주소 공간을 사실상 사용하지 않게 되므로, 초기 복사를 생략함으로써 상당한 시간과 공간을 절약할 수 있다. 또한, 공유 라이브러리의 코드 영역과 같이 다수의 프로세스가 읽기만 하는 데이터는 하나의 물리적 복사본으로 모든 프로세스가 공유할 수 있어 효율적이다.
구현을 위해서는 페이지 테이블 항목에 쓰기 권한을 관리하는 보호 비트가 필요하다. 초기 공유 시에는 모든 페이지를 읽기 전용으로 표시한다. 쓰기 시도로 인한 페이지 폴트가 발생하면, 운영체제의 폴트 핸들러는 이 폴트가 쓰기 시 복사에 의한 것인지 확인한 후, 원본 페이지의 내용을 새로운 프레임에 복사하고, 쓰기를 시도한 프로세스의 페이지 테이블을 새 프레임을 가리키도록 갱신하며, 해당 항목의 쓰기 권한을 부여한다. 다른 프로세스는 여전히 원본 페이지를 읽기 전용으로 참조하게 된다.

성능 측면에서 가상 메모리 관리는 시스템 효율에 직접적인 영향을 미치는 여러 요소를 고려해야 한다. 핵심적인 고려사항은 페이지 폴트 발생 시의 오버헤드와, 과도한 페이지 폴트로 인해 발생하는 스래싱 현상이다.
페이지 폴트는 프로세스가 접근하려는 페이지가 물리 메모리에 존재하지 않을 때 발생한다. 이때 운영체제는 디스크 입출력 작업을 통해 필요한 페이지를 물리 메모리로 적재해야 하며, 이 과정은 상대적으로 매우 느리다. 페이지 폴트 처리 오버헤드는 다음과 같은 단계로 구성된다.
1. 폴트 발생 트랩 처리
2. 디스크에서 대상 페이지 탐색
3. 사용 가능한 물리 프레임 확보 (필요 시 기존 페이지 스왑 아웃)
4. 디스크에서 물리 메모리로 페이지 읽기
5. 페이지 테이블 갱신
6. 중단된 명령어 재실행
이러한 오버헤드는 시스템의 전반적인 응답 시간과 처리량을 저하시키는 주요 원인이 된다. 따라서 페이지 폴트 발생률을 최소화하는 것이 성능 최적화의 핵심이다.
스래싱은 시스템이 페이지 폴트 처리에 대부분의 시간을 소비하여 실제 유용한 작업을 거의 수행하지 못하는 상태를 말한다. 이는 과도한 다중 프로그래밍 정도나 프로세스에 할당된 물리 프레임 수가 부족할 때 발생한다. 스래싱이 발생하면 CPU 이용률이 급격히 떨어지는 현상을 관찰할 수 있다. 스래싱을 해결하거나 완화하기 위한 주요 기법은 다음과 같다.
워킹 셋 모델 적용: 프로세스에 최근 활동한 페이지 집합(워킹 셋)을 유지할 수 있을 만큼의 충분한 프레임을 할당한다.
페이지 폴트 빈도(PFF) 기법: 페이지 폴트 발생률을 모니터링하여, 그 비율이 높으면 프레임을 추가 할당하고 낮으면 프레임을 회수하는 방식으로 동적으로 조정한다.
로컬 교체 정책 채택: 각 프로세스에 고정된 수의 프레임을 할당하고, 페이지 교체가 필요할 때는 해당 프로세스 내의 프레임에서만 교체를 수행한다. 이는 한 프로세스의 과도한 페이지 요구가 다른 프로세스의 성능을 심각하게 저하시키는 것을 방지한다.
다중 프로그래밍 정도 조절: 시스템의 평균적인 페이지 폴트율이 임계값을 초과하면, 일부 프로세스를 일시 중단시켜 메모리에 남아있는 프로세스들에게 더 많은 프레임을 제공한다.
페이지 폴트가 발생하면 운영체제는 디스크 입출력 작업을 포함한 일련의 복잡한 처리를 수행해야 한다. 이 처리 과정에서 소요되는 시간과 자원을 페이지 폴트 오버헤드라고 한다. 페이지 폴트 처리에는 일반적으로 다음과 같은 단계가 포함된다[3].
1. 트랩 처리: CPU는 현재 명령어 실행을 중단하고, 운영체제의 페이지 폴트 핸들러로 제어권을 넘긴다.
2. 페이지 테이블 검증: 요청된 가상 주소의 유효성과 접근 권한을 확인한다.
3. 빈 프레임 탐색: 물리 메모리(RAM)에서 사용 가능한 빈 프레임을 찾는다. 만약 없다면 페이지 교체 알고리즘을 실행하여 희생 프레임을 선택하고 디스크에 기록해야 한다.
4. 디스크 입출력: 필요한 페이지가 저장된 디스크(보조기억장치) 위치로부터 물리 메모리 프레임으로 데이터를 읽어온다. 이 단계는 일반적으로 수 밀리초(ms) 이상 걸리는 매우 느린 작업이다.
5. 페이지 테이블 갱신: 새로 로드된 페이지의 물리 프레임 주소로 페이지 테이블 항목을 갱신하고, 유효 비트를 설정한다.
6. 프로세스 재개: 페이지 폴트를 일으킨 프로세스를 대기 상태에서 실행 가능 상태로 변경하고, 중단된 명령어부터 실행을 재개한다.
페이지 폴트 오버헤드는 시스템 성능에 직접적인 영향을 미친다. 오버헤드의 주요 구성 요소는 다음과 같다.
오버헤드 요소 | 설명 |
|---|---|
디스크 입출력 시간 | 디스크 헤드 이동(탐색 시간)과 데이터 전송 시간으로, 전체 오버헤드의 대부분을 차지한다. |
컨텍스트 스위칭 | 사용자 모드에서 커널 모드로의 전환 및 핸들러 실행에 소요되는 CPU 시간이다. |
페이지 교체 작업 | 희생 페이지가 더티 페이지[4]인 경우, 이를 디스크에 다시 쓰는 추가 입출력이 발생한다. |
따라서 성능 최적화를 위해 TLB(변환 색인 버퍼) 히트율을 높이고, 지역성을 고려한 페이지 교체 알고리즘을 사용하며, 페이지 프리페칭 기법을 적용하는 등의 방법으로 페이지 폴트 발생 빈도를 줄이는 것이 중요하다.
스래싱은 시스템이 지속적으로 페이지 폴트를 처리하는 데 대부분의 시간을 소비하여 실제 유용한 작업을 거의 수행하지 못하는 상태를 가리킨다. 이 현상은 프로세스가 실행에 필요한 최소한의 페이지 프레임 수보다 적은 프레임을 할당받았을 때 주로 발생한다. 프로세스가 활발하게 사용하는 페이지 집합인 워킹 셋이 메모리에 온전히 상주하지 못하면, 프로세스는 페이지를 메모리로 불러오는 입출력 작업이 끝나기를 기다리는 동안 대부분의 시간을 블록된 상태로 보내게 된다. 이로 인해 CPU 이용률이 급격히 떨어지고, 운영체제는 이를 더 많은 프로세스를 메모리에 적재함으로써 해결하려 시도하는 악순환이 반복된다.
스래싱을 해결하거나 완화하기 위한 주요 방법은 다음과 같다.
접근 방식 | 설명 |
|---|---|
워킹 셋 모델 적용 | 프로세스의 워킹 셋을 추정하여, 해당 집합이 메모리에 머무를 수 있을 만큼 충분한 페이지 프레임을 할당한다. |
페이지 폴트 빈도 기반 조정 | 페이지 폴트 발생률을 모니터링하여, 빈도가 너무 높으면 프레임을 추가 할당하고, 너무 낮으면 프레임을 회수한다. |
각 프로세스에게 고정된 수의 프레임을 할당하고, 해당 프로세스 내에서만 페이지 교체가 일어나도록 한다. 이는 한 프로세스의 과도한 페이지 요구가 다른 프로세스의 프레임을 빼앗지 못하게 함으로써 스래싱의 확산을 방지한다. | |
스래싱이 감지되면, 하나 이상의 프로세스를 전체적으로 보조기억장치로 내보내서(스왑 아웃) 남은 프로세스들에게 충분한 프레임을 제공한다. |
또한, 메모리 압축 기술이나 더 빠른 SSD를 스왑 공간으로 활용하는 것도 페이지 교체의 오버헤드를 줄여 스래싱의 영향을 경감시키는 현대적인 방법이다. 근본적으로 스래싱은 다중 프로그래밍의 정도를 적절히 제한하고, 프로세스에 필요한 최소한의 물리 메모리를 보장함으로써 예방할 수 있다.

리눅스 커널의 가상 메모리 관리자는 페이지 테이블을 통해 각 프로세스에 4GB(32비트 시스템 기준)의 가상 주소 공간을 제공한다. 이 공간은 사용자 공간과 커널 공간으로 나뉘며, 커널 공간은 모든 프로세스에 매핑되어 시스템 호출 시 문맥 교환 없이 효율적으로 접근할 수 있다. 메모리 영역은 vm_area_struct 구조체로 관리되어 가상 주소의 연속적인 구간과 그 속성(읽기, 쓰기, 실행 권한 등)을 기술한다. 페이지 교체는 LRU 알고리즘의 변형을 사용하며, 스왑 공간과의 입출력을 통해 물리 메모리가 부족할 때 페이지를 디스크로 내보낸다.
마이크로소프트 윈도우의 가상 메모리 관리자는 프로세스마다 독립적인 4GB(32비트 x86) 또는 훨씬 더 큰(64비트) 가상 주소 공간을 할당한다. 이 공간은 사용자 모드와 커널 모드 영역으로 분리되어 있다. 윈도우는 요구 페이징과 쓰기 시 복사 기법을 적극 활용하여 메모리 사용을 최적화한다. 페이지 프레임 데이터베이스라는 내부 자료 구조를 사용하여 모든 물리 메모리 페이지의 상태를 추적하고, 작업 집합 관리자를 통해 각 프로세스의 활성 페이지 집합을 관리한다. 시스템 가상 주소 공간은 캐시, 페이징 풀, 비페이지 풀 등 핵심 커널 구성 요소를 위해 예약되어 있다.
두 시스템 모두 하드웨어 지원을 최대한 활용한다. 인텔 및 AMD 프로세서의 MMU와 TLB는 주소 변환을 가속화하며, 최근 시스템에서는 다단계 페이지 테이블 구조를 사용하여 메모리 오버헤드를 줄인다. 또한, 큰 페이지 지원을 통해 TLB 미스를 줄이고 데이터베이스나 가상화 환경과 같은 대용량 메모리 애플리케이션의 성능을 향상시킨다.
리눅스 커널의 가상 메모리 관리 시스템은 페이징을 기반으로 하며, 각 프로세스에 독립적인 4GB(32비트 시스템 기준)의 가상 주소 공간을 제공한다. 이 공간은 일반적으로 사용자 공간(0~3GB)과 커널 공간(3~4GB)으로 나뉜다. 커널은 페이지 테이블을 통해 가상 주소를 물리 주소로 변환하며, TLB를 활용하여 변환 속도를 높인다.
리눅스는 요구 페이징 방식을 사용하여 실제 필요한 페이지만 물리 메모리에 적재한다. 페이지 폴트가 발생하면 커널은 해당 페이지를 스왑 영역이나 디스크의 실행 파일에서 읽어와 물리 메모리에 할당한다. 메모리 부족 시에는 페이지 프레임 회수 알고리즘이 활성화되어 사용 빈도가 낮은 페이지를 스왑 아웃시킨다.
메모리 영역 관리에는 가상 메모리 영역 구조체가 핵심 역할을 한다. 이 구조체는 프로세스의 가상 주소 공간 내 연속된 구간(코드, 데이터, 힙, 스택, 메모리 매핑 파일 등)의 시작 주소, 크기, 접근 권한(읽기, 쓰기, 실행) 정보를 관리한다. 커널은 이 정보를 바탕으로 페이지 테이블을 설정하고, mmap 시스템 호출을 통한 파일 매핑이나 공유 메모리 구축을 처리한다.
성능 최적화를 위해 리눅스는 여러 기법을 적용한다. 파일 입출력 성능 향상을 위한 페이지 캐시는 파일 데이터를 메모리에 캐싱하며, 이 캐시는 가상 메모리 시스템과 통합되어 관리된다. 또한, 쓰기 시 복사 기법을 통해 프로세스 fork 시 메모리 복사 오버헤드를 줄이고, 거대 페이지 지원을 통해 TLB 미스율을 감소시킨다.
마이크로소프트 윈도우 운영체제는 x86-64 아키텍처를 기준으로 64비트 프로세스에 대해 매우 넓은 가상 주소 공간을 제공한다. 일반적으로 사용자 모드 애플리케이션은 128TB(테라바이트)의 가상 주소 공간을 사용할 수 있다[5]. 이 공간은 낮은 주소 영역(사용자 공간)과 높은 주소 영역(커널 공간)으로 나뉜다. 커널 모드 코드와 데이터는 사용자 모드 프로세스에서 접근할 수 없는 높은 주소 영역에 상주하여 시스템 보안을 유지한다.
주소 공간의 레이아웃은 프로세스마다 생성되는 페이지 테이블에 의해 관리된다. 윈도우는 요구 페이징 방식을 사용하여 물리 메모리가 실제로 필요할 때만 페이지를 할당한다. 또한 쓰기 시 복사 기술을 활용하여 프로세스 생성 시 메모리 페이지를 효율적으로 공유하고, 수정이 발생할 때만 복사본을 만들어 메모리 사용량을 최적화한다.
주요 가상 주소 영역의 구성은 다음과 같다.
주소 범위 (대략적) | 용도 | 비고 |
|---|---|---|
낮은 주소 (예: 0x00000...) | 예약됨/널 포인터 접근 방지 | 일반적으로 할당되지 않음 |
사용자 모드 힙/스택 | 애플리케이션 코드, 힙, 스택, DLL | 프로세스별로 독립적 |
높은 주소 (예: 0x7FFF...) | 커널 공간 | 시스템 전역, 사용자 모드 접근 불가 |
이러한 설계를 통해 각 프로세스는 커다란 연속적인 메모리 공간을 갖는 것처럼 프로그래밍할 수 있으면서도, 물리 메모리와 보호 메커니즘은 운영체제가 효율적으로 관리한다. 주소 공간 배치 난수화 같은 보안 기법도 가상 주소 공간 레이아웃에 적용되어 악성 코드의 공격을 어렵게 만든다.