각각의 프로세스가 하나의 메모리 공간을 같이 사용할 때,
프로세스 A에서 프로세스 B가 할당받은 공간을 침범하여 사용하게 되면
프로세스 B는 정상적인 동작을 할 수 없게 된다.
또는 어떠한 프로세스가 OS코드를 침범하게 된다면 더 이상 컴퓨터를 사용하지 못할 수도 있게 되는 현상이 발생할 수 있다.
이를 방지하기 위해 Protection이라는 개념이 생겨났다.
Base Register: 프로세스의 시작 주소
Limit Register: 프로세스가 할당받은 공간의 크기
프로세스가 구동할 때,
Base Register Used Address Base + Limit Register
인 공간에만 메모리를 사용할 수 있다.
범위를 벗어난 메모리에 접근하려 하면 강제적으로 프로세스를 종료해버린다.
이 때 발생하는 오류가 Segmentation Fault / Bus Error
Logical Address
CPU에서 나오는 Address를 Logical (Virtual) Address라 한다.
이 Logical Address의 묶음을 Virtual Address Space라 한다.Logical Address가 생긴 이유는,
각각의 프로세스가 자신의 시작 번지를 0으로 생각하고
범위를 로 생각하도록 하는게 가능하기 때문에,
개발자가 DRAM의 주소를 신경쓰지 않고 개발할 수 있도록
도와주기 위해 도입되었다.Physical Address
DRAM의 주소를 Physical Address라 한다.
이 Physical Address의 묶음을 Physical Address Space라 한다.Virtual(Process) Address Space의 한 Virtual Address에 있는 데이터는
DRAM의 한 Physical Address에 저장되어 있다.
CPU에서 나온 Virtual Address를 알맞은 Physical Address로 변환해 주는 작업을 MMU(Memory Management Unit)에서 담당한다.
MMU에는 Relocation Register라는 것이 존재하여,
CPU에서 나온 Virtual Address에 Relocation Register에 있는 값만큼을 더해
Physical Address를 얻은 후 그 주소로 DRAM에 접근하게 된다.
이 방법은 실제 컴퓨터를 제작할 때에는 쓰이지 않고, 이론적인 방법이다.
위의 구조는 MMU에서 Memory Protection을 수행하는 구조이다.
먼저 실행될 프로세스의 PCB에서 Base, Limit Register을 MMU에 넣게 된다.
이 때 Limit Register = PCB.Limit, Relocation Register = PCB.Base
그 다음 CPU에서 Virtual Address가 MMU에 들어오게 되면,
MMU는 먼저 해당 주소가 Limit Address를 넘어섰는지 확인한다. (Protection)
그 후 Relocation Register의 값을 더해 Physical Address를 생성하여
DRAM에 접근하게 된다.
위의 그림처럼, 하나의 프로세스 메모리 사이에
다른 프로세스의 메모리가 끼어 있다면
이전의 방법으로는 Protection을 지키기 어려워진다.
이를 방지하기 위해 (중간에 끼어있지 못하게 하기 위해)
프로세스의 메모리 공간을 항상 연속적으로 할당해 주는 것을
Contiguous Memory Allocation이라 한다.
External Fragmentation (메모리 조각화)
메모리를 연속적으로 할당하게 되면,
위의 사진처럼 공간이 남아있지만 다른 프로세스를 할당할 수 없게 되는 문제가 생기는데, 이를 External Fragmentation이라 한다.Solution
1. Compaction
빈 공간이 생기면 메모리를 앞으로 옮겨 항상 연속적으로
프로세스의 메모리가 할당되도록 하는 방법
메모리가 커지면 작동 시간이 굉장히 오래 걸리고, Overhead가 발생하므로 이 방법은 사용할 수 없다.2. Non-Contiguous Address Space
빈 공간에 프로세스의 메모리를 흩어서 저장하는 방법
위에서 설명한, 한 프로세스의 메모리 사이에 다른 프로세스의 메모리가 있다면
또다시 Protection을 지키지 못하게 되는데, 이를 해결하기 위해
Paging이라는 기법이 도입되었다.
프로세스의 메모리 공간을 DRAM상에서 흩어서 관리하는 방법
위와 같이 Virtual, Physical Memory를 Page단위로 나누어 관리,
쪼개진 DRAM(Physical Memory)의 각각의 조각을 Frame이라 한다.
이 때 각각의 프로세스에서 Page와 Frame을 매핑하기 위한 테이블을 Page Table이라 한다. (Page Size == Frame Size
)
프로세스가 실행되면, Scheduler는 각각의 프로세스에 대한 메모리를
DRAM에 올려야 한다. 이 때 Page Table도 DRAM에 존재한다.
(inode가 disk에 있던 것처럼 page table은 DRAM에 존재)
CPU에서 Virtual Address가 나오면 MMU에게 전달하게 된다.
MMU는 Page Table을 참조하여 하드웨어로만 처리하게 된다.
p
: Page Number, [p + d]
: Virtual Address
f
: Physical Address, [f + d]
: Physical Address
d
: Page Offset
일반적으로 Page Size는 4096B (4KB)를 사용한다고 한다.
이는 OS에서 정하는 것이 아닌, 제조사에서(하드웨어로) 정해주게 된다.
Internal Fragmentation
메모리가 할당되었지만 사용되지 않는 것을
Internal Fragmentation이라 한다.
Page Size를 늘릴수록 Internal fragmentation이 증가하고,
줄일수록 Internal fragmentation이 감소하지만
Page table entry의 개수가 많아진다.따라서 이를 연구한 결과, Page size = 4096이 가장 적합하다는 결론을 내려서 요즘의 컴퓨터 및 스마트폰들은 대부분 4KB를 채택하고 있다.
디스크에 저장된 코드를 실행하게 되면,
DRAM에는 여러 정보들이 저장된다.
코드, 초기화 데이터, 힙, 외부 라이브러리, 스택, ...
이 때 절대 변경되어서는 안되는 부분이 존재한다. (write X)
코드, 외부 라이브러리, ...
이 때 변경을 시도하면 정상적인 실행이 불가능하므로
OS가 강제적으로 프로세스를 종료시킨다.
그래서 Page Table에 protection bit를 추가해
writable: 1, readonly: 0
으로 표시하여 접근을 제어한다.
write
관련 명령어가 들어오면, MMU는 frame 번호와 함께
protection bit를 참조하는데, 이 때 상태가 readonly
이면
OS에게 Exception을 보낸다.
OS는 Exception의 원인을 분석하여 프로세스에게 Signal을 보내는데,
이 때 전달되는 시그널이 SIGSEGV이다.
프로세스의 Virtual Address Space의 일부분만이
DRAM의 Physical Address와 매핑되어 있다.
따라서 어떠한 Page는 Physical Address와 매핑되어 있지 않을 수 있다.
이런 상황이 발생하는 이유는 다음과 같다.
이와 같이 접근하려는 Page가 DRAM에 존재하는지, 그렇지 않은지 판단하기 위해
Valid-Invalid Page가 도입되었다.
만약 Invalid
인 Page를 접근하려고 하면,
CPU는 Page Fault Exception
이라는 이벤트를 발생시킨다.
이를 통해 없는 Page에 접근하려고 하는 프로세스를 강제 종료시킨다.
이 때 표시되는 메시지가 바로 Segmentation Fault이다.
void main()
{
int *ptr = NULL; // INVALID
*ptr = 10; // SEGMENTATION FAULT
}
이를 해결하기 위해선 메모리를 할당해주어야 한다.
void main()
{
int *ptr = NULL; // INVALID
ptr = malloc(sizeof(int)); // VALID, Page Table Mapping
*ptr = 10; // Good
}
전역변수의 경우 Virtual Address Space의
initialized data
라는 공간에 할당받고, Page Mapping이 이루어진다.
지역변수의 경우 Virtual Address Space의
Stack
공간에 할당받고, Page Mapping이 이루어진다.