Computer Science
운영체제의 메모리 관리 5 - Virtual Memory Concept
3/29/2025

Virtual Memory Introduction
이전 글에서는 페이징에 대해 알아보았습니다. 페이징에 대한 내용은 운영체제가 메모리를 관리할 때 사용하는 두 가지의 성질을 파악할 수 있게 해줍니다.
1. 프로세스의 모든 메모리 참조는 논리 주소로 시작되어 실행 시간에 물리 주소로 변환된다.
이는 프로세스가 할당된 이후 스와핑이나 압축이 발생하더라도 문제가 발생하지 않게 해주었습니다.
2. 프로세스는 여러 개의 조각으로 나뉜 뒤 메모리의 연속적이지 않은 곳에 할당될 수 있다.
이를 통해 외부 파편화를 없애고 내부 파편화를 최소화 할 수 있었습니다.
이 두 성질이 존재한다면, 메모리 관리에 있어서 한 단계 더 기술적 발전을 이뤄낼 수 있습니다. 가상 메모리Virtual Memory라는 기술은 '만약 위 두 성질이 존재한다면, 프로세스가 실행되는 동안 메인 메모리에 모든 페이지가 존재할 필요는 없지 않나?'라는 사고에서 시작합니다. 현재 수행되는 명령어가 접근하고자 하는 코드 영역과 데이터 영역만 메모리에 존재한다면, 비록 다른 페이지가 메인 메모리에 없다 하더라도 해당 명령어는 수행될 수 있기 때문입니다.
위와 같은 사고가 실제로 어떻게 동작할 수 있는지 천천히 살펴보겠습니다. 메모리에 새로운 프로세스를 할당한다고 가정합니다. 이 때 운영체제는 프로세스의 모든 조각들을 메모리에 적재하는 것 대신에, 프로그램의 초기화에 필요한 일부 조각들만 메모리에 적재합니다. 지금 할당된 프로세스 조각들, 즉 실제로 메인 메모리에 존재하는 프로세스 조각들의 집합을 주기억 집합resident set이라고 합니다.
프로세스가 실행될 때, 만약 모든 메모리 참조가 주기억 집합 내에 있다면 프로그램은 문제없이 실행됩니다. 페이지 테이블에는 프로세스 조각과 실제 메모리 주소가 매핑되어 있기 때문에, 운영체제는 참조하고자 하는 주소가 적재되어있는지 여부(주기억 집합 내에 있는지에 대한 여부)를 확인할 수 있습니다. 만약 프로세스가 메모리에 존재하지 않는 논리 주소에 접근한다면, 운영체제는 프로세스를 Block 상태로 만들고 디스크 I/O를 통해 논리 주소가 포함되어있는 프로세스 조각을 메모리에 적재합니다. 이 때 저장된 조각의 위치는 페이지 테이블에 기록될 것입니다. 이후 OS는 프로세스를 Ready 상태로 만들어 프로세스가 해당 논리 주소에 접근하는 명령을 수행할 수 있게 만듧니다.
이 방식에서 프로세스의 조각들은 실제로 메인 메모리에 존재하거나, 아니면 디스크에 스왑되어 존재합니다. 프로그래머나 사용자는 실제 메인 메모리에 무엇이 적재되어있는지 알 지 못하며, 더 넓은 메모리를 가지고 있다고 믿게 됩니다. 이러한 관점에서 이 기술을 가상 메모리Virtual Memory라고 부릅니다.
가상 메모리는 기존 방식과는 다르게 프로세스가 디스크 I/O를 위해 Block 되어있는 상황을 증가시키기 때문에 그 효율성에 의심이 생길지도 모릅니다. 과연 가상 메모리는 실용적일까요?
과연 이 방법은 실용적일까?
한 때는 가상 메모리가 실용적인지 아닌지를 두고 많은 논쟁이 오갔으나, 현대에는 수 많은 경험과 연구를 통해 가상 메모리를 사용하는 것이 효율적이라는 것이 의심없는 사실로 자리잡았습니다. 이유는 다음과 같습니다.
1. 더 많은 프로세스가 메인 메모리에 유지될 수 있다.
프로세스의 전체가 아닌 일부만 메모리에 적재하는 방식은, 한정된 메인 메모리에 더 많은 프로세스를 동시에 올릴 수 있게 해줍니다. 이렇게 되면 한 프로세스가 I/O 작업으로 인해 블로킹될 경우, CPU는 대기하지 않고 메모리에 적재되어 있는 다른 프로세스를 즉시 실행할 수 있습니다. 이로 인해 CPU가 유휴 상태로 머무는 시간이 줄어들고, 전체 시스템의 CPU 활용률이 증가하게 됩니다.
2. 프로세스의 크기가 메인 메모리의 물리적 크기보다 커질 수 있다.
이를 통해 컴퓨터 시스템에서 가장 중요한 문제 하나를 해결한 셈입니다. 만약 가상 메모리 방식이 없었다면, 각 프로그램은 그것이 실행되는 컴퓨터의 메인 메모리 용량에 따라 다르게 개발되어야 할 지도 모릅니다. 만약 메인 메모리에서 이를 다 적재할 수 없다면, 프로그래머는 프로그램 내 한정된 메모리 영역을 겹쳐 사용하는overlaying 방식으로 개발해야합니다. 가상 메모리의 도입은 이러한 일들을 운영체제와 하드웨어에 위임함으로써 메모리 관리의 부담을 덜어줍니다.
그럼에도 불구하고, 가상 메모리는 프로세스를 더 많이 Block 상태로 만들기 때문에 비효율적일지도 모릅니다. 다음 상황을 가정해보면 어떨까요?
메인 메모리는 수 많은 프로세스 조각들로 가득 차 있습니다. 프로세스 수행 중 페이지 테이블에 존재하지 않는 논리 주소를 만나 디스크에서 메모리 조각을 가져와야할 때, 현재 메모리 상에 존재하는 페이지 중 하나는 디스크로 내보내야 할 것입니다. 그런데 문맥 교환이 발생하고 다른 프로세스가 수행될 때, 만약 접근해야하는 페이지가 방금 내쫓았던 페이지라면 또 다시 디스크 I/O가 발생합니다. 이처럼 지나치제 잦은 페이지 교체와 디스크 I/O로 인해 CPU 효율이 급격히 떨어지는 현상을 쓰래싱Thrashing이라고 합니다.
쓰래싱을 해결하는 것은 1970년대의 가장 큰 연구 중 하나였고, 이를 위한 다양한 알고리즘이 등장했습니다. 현대 가장 널리 쓰이는 방식은 과거 페이지 참조 기록을 기반으로, 앞으로 사용되지 않을 가능성이 높은 페이지를 예측하여 우선적으로 교체하는 방식입니다.
이러한 사고는 지역성 원칙Principle of Locality에 근간합니다. 지역성 원칙은 프로세스의 데이터 참조가 군집을 이루는 경향이 있음을 말합니다. 따라서, 프로세스가 최근에 접근한 페이지에 다시 접근할 확률은 매우 높고, 가장 과거에 참조한 페이지에 접근할 확률이 낮다는 것은 합리적인 추론입니다. 이는 어떤 페이지를 내쫓아야 할지에 대한 길잡이가 되어 전체 시스템을 효율적으로 동작시키는 기반이 됩니다. 운영체제는 최대한 사용되지 않을 페이지들을 골라 디스크에 보관하고, 현재 사용될법한 페이지들만 메인 메모리에 남겨 프로세스가 Block 상태가 되는 것을 최소화 합니다.
지역성 원칙은 가상 메모리가 효율적으로 동작할 수 있는 방법을 제시합니다. 또한 가상 메모리가 효과적일 수 있기 위해서는 두 가지 조건이 더 필요합니다. 첫 번째로는 하드웨어의 지원이 필요합니다. 두 번째로는 페이지가 메인 메모리와 디스크를 옮겨 다닐 때 이를 관리할 수 있는 효율적인 소프트웨어입니다.
다음 글에서는 가상 메모리를 도입하기 위한 하드웨어적 측면의 기술들에 대해 알아보겠습니다.