현재 메모리 관리의 가장 큰 특징은 물리적 메모리 크기와 프로세스가 올라갈 위치를 신경 쓰지 않고 프로그래밍 하도록 지원합니다. 이러한 메모리 시스템을 가상 메모리라고 합니다.
- 가상 메모리 시스템의 모든 프로세스는 실제 메모리와 별개로 자신이 메모리의 어느 위치에 있는지 상관없이 0번지부터 시작하는 연속된 메모리 공간을 가집니다.
- 가상 메모리는 크게 프로세스가 바라보는 메모리 영역과 메모리 관리자가 바라보는 메모리 영역으로 나뉩니다.
- 가상 메모리의 최대 크기는 컴퓨터 시스템이 가진 물리 메모리의 크기로 한정되며 CPU 비트에 따라 결정됩니다.
- 가상 메모리 시스템에서는 물리 메모리의 내용 중 일부를 스왑 영역으로 옮깁니다. 따라서 가상 메모리의 크기는 물리 메모리와 스왑 영역을 합한 크기입니다.
그렇다면 가상 메모리는 어떤 방식으로 분할할까요?
가변 분할 방식을 이용한 세그멘테이션과 고정 분할 방식을 이용한 페이징 기법이 있습니다. 기본적으로 페이징 기법을 사용하나 페이지 테이블 관리가 어렵다는 단점이 있습니다. 세그멘테이션은 외부 단편화 등의 문제가 있습니다. 가상 메모리 시스템에서는 두 기법의 단점을 보완한 세그멘테이션 - 페이징 혼용 기법을 주로 사용합니다.
가상 메모리 시스템에서 가상 주소는 실제로 물리 주소나 스왑 영역 중 한 곳에 위치하며 메모리 관리자는 가상 주소와 물리 주소를 일대일 매핑 테이블로 관리합니다.
페이징 기법은 고정 분할 방식을 이용한 가상 메모리 관리 기법으로 물리 주소 공간을 같은 크기로 나누어 사용합니다. 가상 주소는 프로세스 입장에서 바라본 메모리 공간으로 항상 0번지부터 시작합니다. 페이징 기법의 특징에 대해서 공부해봅시다.
- 가상 주소의 분할된 각 영역을 페이지라고 하며 번호를 매겨 관리합니다.
- 물리 메모리의 각 영역은 가상 주소의 페이지와 구분하기 위해 프레임이라고 합니다. 프레임 또한 페이지처럼 번호를 매겨 관리합니다.
- 페이지와 프레임의 크기는 같기 때문에 페이지는 어떠한 프레임에도 배치될 수 있습니다.
- 어떤 페이지가 어떤 프레임에 있는 지에 대한 연결(매핑) 정보는 페이지 테이블에 담겨있습니다.
- 페이지 테이블에 invalid는 해당 페이지가 스왑 영역에 있다는 뜻 입니다.
페이지 기법에서 주소를 변환하는 방법에 대해 알아봅시다.
페이지 기법에서는 가상 주소를 VA = <P, D>로 표현합니다. VA는 Virtual Address, P는 페이지, D는 Distance로 거리 혹은 오프셋을 의미합니다. 페이징 기법에서의 주소 변환은 가상 주소 VA = <P, D>를 물리 주소 PA = <F, D>로 변환하는 것입니다. PA는 Physical Address이고 F는 Frame 입니다. 페이징 기법에서 VA가 PA로 변형될 때에 D의 값은 가상 메모리와 물리 메모리를 같은 크기로 분할했기 때문에 변하지 않습니다.
페이지의 크기가 다양할 경우 가상 주소를 <P, D>로 변환하는 공식은 다음과 같습니다.
P = 나눗셈(가상 주소/한 페이지의 크기)의 몫
D = 나눗셈(가상 주소/한 페이지의 크기)의 나머지
예를 들어 한 페이지의 크기가 512B인 시스템에서 가상 주소 2049번지는 2049/512는 몫이 4, 나머지가 1이기 때문에 P = 4, D = 1이 됩니다.
16bit CPU의 컴퓨터에서 한 페이지의 크기가 2^10B일 때 페이징 시스템에 대해 알아봅시다. 한 프로세스가 사용할 수 있는 가상 메모리의 크기는 2^16B입니다. 따라서 사용자는 0번지부터 2^16-1번지까지 가상 주소 공간을 사용 가능합니다. 또한 가상 주소로 사용할 수 있는 16bit 중 6bit는 페이지 번호로 10bit는 페이지의 처음 위치에서 해당 주소까지의 거리를 저장합니다. 이것은 시스템의 페이지가 0~63번지까지, 페이지 하나가 0~1023번 까지 구성되어 있다는 것을 의미합니다. 이러한 상황에서 가상 주소 980번지의 페이지와 거리를 구하려고 하면 페이지 하나의 크기가 1024이므로 980/1024를 하여 몫은 0, 나머지는 980으로 하여 VA = <0, 980>과 같은 결과를 얻어 낼 수 있습니다.
그렇다면 다수의 프로세스가 있는 경우 페이징 시스템은 어떻게 될까요? 페이지 테이블 관리가 복잡한 이유는 시스템에 여러 개의 프로세스가 존재하고 프로세스마다 페이지 테이블이 하나씩 존재하기 때문입니다. 프로세스의 수가 많아지면 페이지 테이블의 크기가 커지고 이에 따라 프로세스가 실제로 사용할 수 있는 메모리 영역이 줄어듭니다. 따라서 페이지 테이블의 크기를 적정하게 유지하는 것은 페이지 테이블 관리의 핵심이고 페이지 테이블은 메모리 관리자가 자주 사용하는 자료구조이므로 물리 메모리 영역 중 운영체제 영역의 일부분에 모아 놓습니다.
이렇게 페이지 테이블을 운영체제 영역의 일부분에 모아 놓으면 운영체제의 영역이 커지는 만큼 사용자 영역이 작아집니다. 따라서 물리 메모리의 크기가 작을 때는 프로세스만 스왑 영역으로 옮겨지는 것이 아니라 페이지 테이블의 일부도 스왑 영역으로 옮겨집니다. 각 페이지 테이블의 시작 주소는 페이지 테이블 기준 레지스터(Page Table Base Register, PTBR)에 보관하여 각 프로세스가 메모리에 접근하려고 할 때 메모리 관리자는 페이지 테이블의 위치를 신속하게 파악할 수 있습니다. PTBR은 각 프로세스의 PCB에 저장되는 데이터로 물리 메모리 내에 페이지 테이블의 시작 주소를 가지고 있습니다.
위의 페이지 테이블의 관리에서 기본적으로 페이지 테이블은 운영체제 영역에 존재하며 때에 따라 스왑 영역에 존재하기도 합니다. 페이지 테이블 전체를 메모리에서 관리하느냐 일부를 스왑 영역에서 관리하느냐에 따라 가상 주소를 물리 주소로 변환하는 방법이 달라집니다. 페이지 테이블이 위치하는 곳에 따라 다양한 페이지 테이블 매핑 방식이 존재합니다.
직접 매핑(direct mapping)
- 페이지 테이블 전체가 물리 메모리의 운영체제 영역에 존재하는 방식입니다.
- 별다른 부가 작업 없이 바로 주소 변환이 가능하기 때문에 직접 매핑이라고 부릅니다.
연관 매핑(associative mapping)
- 페이지 테이블 전체를 스왑 영역에서 관리하는 방식입니다.
- 물리 메모리의 여유 공간이 작을 때 사용하는 방식입니다.(따라서 최근에는 사용하지 않습니다.)
- 모든 페이지 테이블을 저장 장치의 스왑 영역에 저장하고 그 중 일부만 물리 메모리에 가져옵니다.
- 일부 내용만 무작위로 가져오기 때문에 페이지 번호와 프레임 번호를 모두 표시합니다.
- 주소 변환 시 물리 메모리 내의 페이지 테이블을 다 검색해야 하며 만약 원하는 프레임 번호를 얻지 못하면 스왑 영역에 있는 페이지 테이블을 검색합니다.
- 검색 실패 시 스왑 영역에서 다시 찾아야 하므로 시간을 낭비하여 속도가 느려지게 됩니다.
집합-연관 매핑(set-associative mapping)
- 디렉토리 매핑이라고도 부릅니다.
- 페이지 테이블을 일정한 집합으로 나누고 나눈 단위로 물리 메모리에 가져옵니다.
- 페이지 테이블을 n개씩 나누고 이를 관리하는 페이지 테이블을 하나 더 생성합니다.
- 새로 생성한 집합 테이블에는 일정하게 나눈 페이지 테이블이 물리 메모리에 있는지, 스왑 영역에 있는지에 대한 위치 정보를 표시합니다. I는 스왑 영역에 있다는 표시입니다.
- 연관 매핑과 비교했을 때 집합 테이블을 통해 원하는 페이지 테이블 엔트리가 스왑 영역에 있는지 물리 메모리 영역에 있는지 간단하게 파악할 수 있습니다.
- 연관 매핑과 집합-연관 매핑은 캐시에서 사용하는 방식입니다.
- 페이지 테이블이 일정 크기의 묶음으로 나뉘기 때문에 가상 주소를 VA = <P, D>가 아니라 VA = <P1(디렉터리 테이블 번호), P2(묶음 테이블 번호), D>로 바꾸어 표시합니다.
역매핑(invert mapping)
- 물리 메모리의 프레임 번호를 기준으로 테이블을 구성합니다.
- 물리 메모리의 프레임에 어떤 프로세스의 어떤 페이지가 올라와 있는지 표시합니다.
- 프로세스 수와 상관없이 테이블이 하나만 존재하므로 테이블의 크기가 매우 작다는 장점이 있습니다.
- 프로세스가 가상 메모리에 접근할 때 PID와 페이지 번호를 모두 찾아야 하기 때문에 속도가 매우 느리다는 단점이 있습니다.
지금까지는 페이징 기법의 구현에 대해 살펴보았습니다. 이제 가변 분할방식인 세그멘테이션 기법의 구현에 대해 공부해봅시다.
- 세그멘테이션 테이블에는 세그먼트의 크기를 나타내는 limit와 물리 메모리 상의 시작 주소를 나타내는 address가 있습니다.
- 프로세스 크기에 따라 메모리를 분할하기 때문에 매핑 테이블에 크기 정보를 포함합니다.
- 각 세그먼트가 자신에게 주어진 메모리 영역을 넘어가면 안되기 때문에 세그먼트의 크기 정보에는 크기를 뜻하는 size 대신 제한을 뜻하는 limit를 사용합니다.
- 스왑 영역에 존재하는 프로세스는 세그멘테이션 테이블의 address에 I(Invalid)라고 표시합니다.
- 메모리를 프로세스 단위로 관리하기 때문에 페이지 테이블이 작고 단순하다는 장점이 있습니다.
- 물리 메모리의 외부 단편화로 인해 관리가 복잡합니다.
- 만약 가상 주소의 거리가 세그먼트의 크기보다 크다면 메모리 결함(fault)를 출력하고 해당 프로세스를 강제 종료합니다.
- 자신의 영역을 벗어나는 주소에 접근하거나 숫자를 0으로 나누는 것과 같이 의도치 않은 인터럽트를 트랩이라고 하며 트랩이 발생하면 운영체제는 사용자에게 세그멘테이션 오류(segmentation fault) 메시지를 보냅니다.
페이징 기법은 물리 메모리를 동일한 크기로 나누어 관리하기 때문에 메모리 관리가 단순한 반면 페이지 테이블의 크기가 컸습니다. 세그멘테이션 기법은 맵핑 테이블의 크기가 작지만 물리 메모리의 단편화로 추가적인 관리가 필요했습니다. 이러한 두 가지 방법의 장점을 활용한 것이 세그멘테이션-페이징 혼용 기법입니다. 이 기법을 이해하기 위해서는 먼저 프로세스의 영역별 메모리 접근 권한에 대해 알아야 합니다.
프로세스는 몸체에 해당하는 코드 영역, 프로세스가 사용한느 데이터를 저장하는 데이터 영역, 프로세스를 실행하는데 필요한 스택 영역, 프로세스 제어블록(PCB)로 구성됩니다.
- 코드 영역 : 자기 자신을 수정하는 프로그램은 없기 때문에 읽기 및 실행 권한을 가집니다.
- 데이터 영역 : 데이터는 크게 읽거나 쓸 수 있는 데이터와 읽기만 가능한 데이터로 나눌 수 있습니다. 일반적인 변수는 읽거나 쓸 수 있으므로 읽기 및 쓰기 권한을 가지고 상수로 선언한 변수는 읽기 권한만 가집니다.
메모리 접근 권한 검사는 가상주소에서 물리주소로 변환이 생기면 시행됩니다. 이 부분이 핵심인데 이렇게 가상주소에서 물리주소로 변환하는 과정에서 페이징 기법을 사용할 경우 페이지 테이블의 모든 행에 메모리 접근 권한과 관련된 권한 비트(right bit)를 추가해야 합니다. 페이지 테이블에 권한 비트가 추가되면 페이지 테이블의 크기가 커지는 문제가 생깁니다. 이러한 문제를 해결하기 위해 세그멘테이션 기법을 혼용하는 것 입니다.
위의 그림과 같이 페이징 기법에 세그멘테이션 테이블을 추가하고 권한 비트와 같은 중복 데이터를 세그멘테이션 테이블로 옮겨 테이블의 크기를 줄입니다. 오늘날 대부분의 운영체제는 이와 같은 방식을 사용하고 있습니다. 사용자 입장에서는 기본적으로 세그멘테이션 기법을 사용하고 메모리 관리자 입장에서는 페이징 기법을 사용합니다. 가상주소 VA는 <S, P, D>로 표현하여 S는 세그먼트 번호, P는 페이지 번호, D는 거리를 의미합니다.
- 사용자가 어떤 주소에 있는 데이터를 요청하면 해당 주소가 몇 번째 세그먼트의 몇 번째 페이지로부터 얼마나 떨어져 있는지 계산하여 가상 주소 VA = <S, P, D>를 구합니다.
- 세그멘테이션 테이블의 해당 세그먼트 번호로 가서 자신의 영역을 벗어나는 접근인지 등을 확인합니다.
- 페이지 테이블에서 해당 페이지가 어느 프레임에 저장되었는지 찾습니다. 만약 없다면 스왑 영역에 가서 해당 페이지를 물리 메모리로 가져옵니다.
- 물리 메모리에 있는 프레임의 처음 위치에서 D만큼 떨어진 곳에 접근하여 데이터를 읽거나 씁니다.