13.1 초기 시스템
초기의 시스템의 메모리는 매우 단순했다. 0~64KB의 메모리를 운영체제가 사용했고, 나머지 메모리는 하나의 실행 중인 프로그램(프로세스)가 사용했다.
13.2 멀티 프로그래밍과 시분할
하지만 컴퓨터를 더 효과적으로 사용하기 위해 멀티 프로그래밍(multi-programming)이 등장했다. 멀티 프로그래밍이란 하나의 CPU를 가지고 작업하던 중 어느 프로세스가 I/O 처리를 하게 되었을 때, 그 입출력 결과를 무한히 기다리는 대신 다음 프로세스 작업을 진행하는 것이다. 준비 상태에 있는 프로세스로 전환하는 것은 운영체제의 몫이다. 따라서 CPU의 이용률이 늘어나게 되었다.
그 이후 시분할(time-sharing) 방식도 도입되었다. 시분할을 구현하는 한 가지 방법은 하나의 프로세스를 짧은 시간 동안 실행시키는 것이다. 하나의 프로세스가 실행되는 기간 동안 프로세스에게 모든 메모리를 접근할 권한이 주어진다. 그 후 이 프로세스를 중단하고, 중단 시점의 모든 상태를 디스크에 저장하고, 다른 프로세스의 상태를 탑재하여 또 짧은 시간 동안 실행시킨다. 이 방법은 메모리 내용 전체를 디스크에 저장해야 하기 때문에 메모리가 커질 수록 매우 느려진다.
위 그림에서는 세 개의 프로세스가 512KB의 물리 메모리에서 각기 작은 부분을 할당 받았다. 근데 한 프로세스가 다른 프로세스의 메모리를 읽거나 악의적으로 사용하면 안된다. 따라서 프로그램이 메모리에 동시에 존재하기 위해서는 보호(protection)의 문제가 해결되어야 한다.
13.3 주소 공간
우리는 보호의 문제를 해결하기 위해 사용하기 쉬운 메모리 개념을 만들어야 한다. 이 개념이 주소 공간(address space)이다. 운영체제의 메모리 개념을 이해하는 것이 메모리를 어떻게 가상화할지를 이해하는 핵심이다. 주소 공간은 실행되는 프로그램의 모든 메모리 상태를 갖고 있다.
- 코드(Code) : 프로그램의 코드, 명령어가 담김. 코드는 정적이기 때문에 메모리에 저장하기 쉬움. 따라서 주소 공간의 상단에 배치. 추가 메모리를 필요로 하지 않음.
- 스택(Stack) : 함수 호출 체인 상의 현재 위치, 지역 변수, 함수 인자와 반환 값 등을 저장.
- 힙(Heap) : 동적으로 할당되는 메모리를 위해 사용 (ex) C언어의 malloc(), Java의 new)
- Data(실행 파일에 포함) : 초기값이 있는 전역 변수와 정적 변수를 저장한다. 런타임 중에 변수에 접근하여 값을 변경할 수 있다.
- Data(BSS, Blocked Started by Symbol) : 초기값이 없는 전역 변수와 정적 변수를 저장한다. 프로그램의 실행과 함께 커널에 의해 0으로 초기화 된다.
Data 세그먼트와 BSS 세그먼트를 구분하는 이유는 메모리 공간을 효율적으로 사용하기 위함이라고 한다. Data 세그먼트는 초기값을 가지고 있으므로 ROM 메모리에 저장하되, 변수로써 사용하기 위해서 프로그램 실행과 함께 RAM 메모리로 불러와 사용한다. BSS 세그먼트는 초기값을 가지고 있지 않으므로 굳이 ROM에 저장하지 않는다. 프로그램을 수행하면서 0으로 초기화하여 RAM 메모리로 불러와 사용한다.
그런데 우리는 프로세스가 자신이 메모리 전체를 사용한다고 믿게 하고 싶다. 현실은 하나의 물리 메모리를 여러 프로세스가 공유하고 있는 것이지만 말이다. 운영체제가 메모리를 가상화(virtualizing)하여 이를 수행한다. 각 프로세스는 주소 0으로부터 연산을 수행하겠지만, 사실 0은 물리 주소가 아닌 가상 주소이고, 이 가상 주소를 운영체제가 물리 주소 320KB(예를 들면)으로 변환하는 것이다. 이 변환 과정에서는 하드웨어(MMU 등)의 지원을 받는다.
13.4 메모리 가상화의 목표
1. 투명성(transparency)
운영체제는 프로세스가 가상 메모리의 존재를 인지하지 못하도록 가상 메모리 시스템을 구현해야 한다. 프로세스가 자신이 전용 물리 메모리를 소유했다고 착각하게 해야 한다. 많은 작업들이 메모리를 공유할 수 있도록, 무대 뒤에서 운영체제와 하드웨어는 모든 작업을 수행한다.
2. 효율성(efficiency)
운영체제는 가상화가 시간과 공간 측면에서 효율적이도록 해야한다. 프로그램이 너무 느리게 실행되서는 안되고, 가상화를 위한 구조를 위해 너무 많은 메모리를 사용해서도 안된다. 이를 위해 운영체제는 TLB 등의 하드웨어 지원을 받는다.
3. 보호(protection)
운영체제는 프로세스를 다른 프로세스로부터 보호해야 하고, 운영체제 자신도 프로세스로부터 보호해야 한다. 한 프로세스가 Load, Store, Fetch 등을 실행할 때 다른 프로세스나 운영체제의 메모리 내용에 접근하거나 영향을 줄 수 있어서는 안된다. 즉 프로세스들을 서로 고립(ioslate)시킬 수 있어야 한다. 이를 위해 하드웨어의 지원을 받는다. CPU의 커널 모드에서만 메모리 내용 접근을 허용하고, MMU로 주소 변환을 한다.
'운영체제' 카테고리의 다른 글
[운영체제] 07. 스케줄러 (0) | 2024.04.23 |
---|---|
[운영체제] 18. Paging (1) | 2024.04.07 |
[운영체제] 06. 제한적 직접 실행(LDE, Limited Direct Execution) (1) | 2024.03.31 |
[운영체제] 16. segmentation 세그멘테이션 (1) | 2024.03.24 |
[운영체제] 15. vm mechanism 주소 변환의 원리 (1) | 2024.03.24 |