Post List

2018/03/04

System__가상메모리1

이번에는 가상메모리에 대해 알아보겠습니다. 한번쯤 '메인 메모리는 512M바이트인데 어떻게 프로세스에 4G바이트가 할당되어 프로그램이 실행되는지'에 대한 의문이 들 때가 있었을 것입니다.

오늘은 이러한 의문을 해결해줄 수 있는 가상메모리에 대해 알아볼것이고 그 전에 물리 주소에 대해서 먼저 이야기해보겠습니다. 

물리주소(Physical Address)
용량이 16M바이트일때, CPU 접근가능한 메모리 영역은 0번지부터 '(16x1024x1024)-1'번지 사이가 됩니다. 이것은 실제 물리적인 메인 메모리의 주소 범위에 해당하며, 이렇게 주소를 할당하는 것을 가리켜 물리적 주소 지정이라 합니다. 물리적 주소 지정의 특징은 메인 메모리 크기에 따라서 지정 가능한 주소의 범위가 결정되는 입니다.

이처럼 물리적 주소 지정을 하게 되면 CPU입장에서는 접근 가능한 주소의 범위가 제한됩니다. 이말은 , 프로그래머가 할당할 있는 주소 범위가 제한적이라는 뜻도 됩니다. 이렇게 주소의 범위가 제한되면, 프로그래머는 주소 범위를 넘어서지 않도록 주의를 기울이며 개발에 임해야 합니다.
메인 메모리크기가 16M바이트이면 범위 안에서 운영체제와 프로그램을 로딩하고 프로그램 실행과정에서 메모리를 할당해야만 한답니다.

32비트 시스템에서 프로세스 생성 4G바이트의 메모리를 할당받을 있습니다. 그러나 메인 메모리의 크기는 여기에 턱없이 부족합니다.
따라서 4G바이트는 실제 존재하지 않는 가상의 주소라는 결론을 내릴 있습니다. 이렇게 가상의 주소를 지정하는 것을 가리켜 가상 주소 지정(virtual Addressing)이라 하며, 가상 주소 지정을 통해서 할당받게 되는 4G바이트를 가리켜 가상 메모리 공간(Virtual Address Space) 합니다.
이는 이상의 프로세스에게도 각각 4G바이트 메모리 공간 할당이 이루어집니다.

하지만 간단한 Hello world를 출력해주는 프로그램을 실행시킬때 4G바이트씩 할당이 이루어진다면 엄청난 메모리 낭비와 시간낭비가 아닌가 하는 생각이 듭니다.

하지만 가상 메모리 시스템을 이해하고 나면 위와 같은 문제가 해결되는 원리를 이해할 수 있으며, 가상 메모리 시스템을 구현하는 방법은 표준으로 정해져 있지 않기때문에, 대부분의 시스템에서 페이징이라는 기법을 사용하므로 이를 바탕으로 설명하겠습니다. 

64K-1까지 주소 지정을 할 수 있는 16비트 시스템에서 프로세스별로 가상 메모리를 포함한 64K바이트 메모리를 할당이 이루어지고 메인 메모리 16K바이트라는 가정하에 예를 들어보겠습니다. 
실제 메모리는 16K바이트가 전부인데, 프로세스를 생성할 때마다 64K바이트를 할당하고자 하면 문제가 발생합니다. 특히 16K번지 이상의 메모리는 접근초자 불가능합니다. 최대 할당 가능한 메모리는 16K-1 번지이니까요.

프로그램이 실제로 64K바이트를 전부 사용하지 않을 확률이 높다는 데에서 힌트를 얻을 있습니다.


그림을 보면 MMU라는게 등장합니다. MMU 16K바이트밖에 존재하지 않는 메모리를 64K바이트가 존재하는 것처럼 CPU 느끼도록 컨트롤하는 역할을 합니다. ( 32비트 시스템에서는 4G바이트 메모리가 존재하는 것처럼 느끼게 해줍니다). 그림에는 MMU CPU 독립적인 하드웨어로 표시해 뒀지만, 실제로는 CPU 함께 하나로 패키징 되는 장치입니다. CPU 메모리로 직접 접근하지 않고 MMU 통해서 요청합니다.


요청을 받은 MMU 메인 메모리에서 아직 사용되지 않는 메모리 블록 하나를 골라서 할당을 합니다. 그럼 한가지 의문이 들죠,
그림에서는 4K바이트로 메인 메모리를 나눠놨는지 입니다. , 1K번지에서부터 20바이트만 요청하였는데, 메인 메모리 4K바이트 블록의 용도가 모두 지정되었습니다.

그림에서는 메모리 할당의 단위가 4K바이트인 셈입니다. 때문에 메모리 할당의 범위는 아래와 같이 증가합니다.
0K-4K, 4K-8K, 8K-12K, 12K-16K, 16K-20K, ........
(정확한 표현을 위해서 범위의 끝마다 -1 붙여주어야 한다. 하지만 편의상 생략함.)

만약 블록의 단위를 16바이트 정도로 최소화하거나, 단위를 아예 없애버리고 필요한 만큼만 할당하게 경우 메모리 사용의 효율성은 증가합니다.
그러나 그만큼 MMU 복잡한 일을 해야만 합니다. , 연산이 늘어나게 되고, 이는 속도의 감소로 이어집니다.

예를들어, 12K-13K번지만 필요한 경우에, 나머지 13K-16K번지는 필요 없이 할당이 이루어집니다. 하지만 그렇지 않습니다.
13K-16K번지도 조만간 사용하게 것이기 때문입니다. 프로그램의 '스페이셜 로컬리티' 특성때문이지요.

임의로 정한 블록의 크기 4K바이트는 시스템에 따라서 수백 바이트에서 64K바이트까지 크기가 다양합니다. 이러한 블록을 하드웨어 입장에서는 페이지 프레임이라 하고, 소프트웨어 입장에서는 페이지 합니다. 페이지 프레임은 실제 메인 메모리 블록을 의미하고, 페이지는 가상 메모리 블록을 의미합니다. 물론 페이지 프레임과 페이지의 크기는 일치합니다.

그림은 가상 메모리와 그에 해당하는 실제 물리 메모리가 어떻게 매핑되는지 보여줍니다. 현재 가상 메모리 0K-4k 물리 메모리의 가장 위쪽에 매핑되어 있습니다. 따라서 CPU 0K-4K사이에 존재하는 데이터를 요구할 경우 MMU 매핑된 물리 메모리를 참조해서 데이터를 전송해 줍니다.

MMU 내부적으로 아래의 그림과 같은 정보를 유지하고 있다가 사진에서 보여주는 정보를 저장하고 있습니다. 여기서 주목할 부분은 CPU 요청한 주소의 데이터를 MMU 해석해 나가는 과정입니다. 페이지 크기를 4K바이트 기반으로 하여 설명하고 있습니다.

그림에서 페이지 테이블은 페이지의 크기를 4K바이트로 정의하는 경우 64K바이트의 메모리 공간에서 얻을 있는 페이지 개수는 16입니다.
페이지0 0K-4K 메모리 주소를 페이지15 60K-64K 메모리 주소를 나타냅니다.

페이지 테이블의 키는 페이지 숫자입니다. 그리고 값은 해당 페이지가 존재하는 페이지 프레임의 시작 번지입니다. 이러한 테이블 구성을 지닐 경우 페이지 테이블을 참조해서 가상 주소를 실제 할당되어 있는 물리 주소로 변환할 있습니다.
예를 들어, CPU 10진수로 57354번지에 int 데이터 350 저장하라는 명령을 MMU 내렷다고 합시다.
그렇다면 MMU 일단 가상 주소 57354 해당하는 물리 주소를 찾아야 합니다. 57354 56K + 1번지이기 때문에 14번째 페이지 프레임에 해당한다는 것을 계산해 있습니다. 따라서 페이지 테이블을 통해서 14번째 프레임의 시작 번지를 확인합니다. 실제로 MMU 57354라는 숫자 전부를 참조해서 14번째 프레임이라는 것을 확인하지 않습니다. 57354 2진수로 표현하면 1110 0000 0001 입니다.
중에서 상위 4비트 1110 참조해도 14번째 프레임에 해당한다는 것을 계산할 있으니 전부를 필요는 없습니다.
이렇게 해서 14번째 페이지 프레임이라는 것을 알아 냈습니다. 그렇다면 이제 14번째 프레임 내에서의 특정 위치를 결정해야 합니다.
이는 하위 12바이트를 통해서 있습니다.



이번에는 메모리 부족 문제에 대해 알아보겠습니다. 만약 이미 물리 메모리의 할당이 끝나버린 경우, 이상의 메모리 할당이 불가능한 상황일 게다가 이상의 프로세스가 실행된다고하면 문제입니다. 부족한 메모리를 어떻게 해결해야 하는가 하면 방법은 하드 디스크에 있습니다. 

하드디스크는 램과 비교해서 속도를 제외하면 기능에 있어서 조금도 부족함이 없는 메모리입니다. 이러한 하드디스크를 메인 메모리로 확장해서 문제를 해결할 있습니다. 조금 구체적으로 말하자면 스왑 파일이라는 개념을 도입해서 램에 해당하는 메인 메모리를 하드디스크로까지 확장한 것입니다.

수십 기가바이트 이상의 여유 공간을 메인 메모리로 확장하여 있다는 사실은 아주 장점입니다. 이제 메모리 할당 과정에서 부족한 부분은 하드디스크의 여유 공간으로 대체할 있게 되었습니다. 하드디스크의 장점인 용량으로 메모리 부족에 대한 문제를 해결해 주었지만 속도 저하라는 문제는 여전히 있습니다. 하지만 하드디스크는 스왑 파일을 통해서 메인 메모리를 보조해 주는 것이지, 램과 동일한 성격의 메인 메모리 역할을 하는 것은 아닙니다.


하드디스크의 역할은 아래 그림과 같습니다.

그림과 같이 메모리 4-8K 메모리를 할당해야만 한다고 가정할 , 메인 메모리에 여유 공간이 없으니 방법이 없습니다. 특정 메모리 블록을 하드디스크에 저장하고 나서 영역을 4-8K영역으로 새롭게 할당하는 밖에 없습니다. 그림에서는 8-12K 영역의 블록을 하드디스크에 저장하고 있습니다.

만약에 새로운 할당 이후에 하드 디스크에 저장해버린 8-12K 영역 접근이 발생하면 어떻게 동작할까요?


이전에 저장해 놓은 8-12K 메모리 블록을 다시 램에 가져다 놓기 위해서, 이번에는 0-4K메모리 블록을 하드디스크로 저장하고 있습니다. 여기서 램과 하드디스크 사이의 데이터 이동 기본 단위는 페이지 프레임 크기와 동일하다는 점도 주목해야합니다.

가상 메모리에서 하드디스크의 역할에 대해 알아보았는데, 이를 바탕으로 이상의 프로세스에게 어떻게 4G바이트씩 할당이 가능한지 있습니다.

프로세스 A 실행을 멈추고 프로세스 B 실행시키고자 한다고 가정할 , 현재 메인 메모리 램에는 프로세스 A 실행시키기 위한 데이터가 존재할 것입니다.
그런데 이제 프로세스 B 실행시켜야하는데, 이러한 경우 램에 존재하는 프로세스 A 실행을 위한 데이터 모두를 프로세스 A 스왑 파일에 저장합니다.
그리고 프로세스 B 실행을 위한 데이터를 프로세스 B 스왑 파일로부터 램에 가져다 놓습니다. 이러한 일련의 과정을 반복하면서 이상의 프로세스가 각각 4G바이트의 메모리를 할당받아서 실행을 이어가는 것입니다.


이제 하드디스크의 역할이 분명해졌습니다. 어떤식으로 램과 더불어 메인 메모리를 확장하는지 이해될 것입니다. 그림은 MMU 관계를 정의할 있습니다.
그렇다면 가상 메모리 시스템은 MMU 의해 완성되는 것인가라는 의문이 듭니다.
대답은 아니요! 이며, 가상 메모리에서 메모리 구성에 필요한 시스템의 기본 기능(메모리의 할당과 주소 변환) 관련된 내용들만 MMU 처리하고, 이를 바탕으로 Windows 운영체제의 VMM 사용자(개발자)측면 기능을 완성합니다.