메모리의 범위와 종류
컴퓨터를 구성하는 요소 중에서 임시적이든, 영구적이든 저장 기능을 조금이라도 가지고 있으면 무조건 메모리의 범위에 포함이 된다. 그럼 메모리라 불릴 수 있는 요소들을 나열해 보자.
메인(Main) 메모리
가장 먼저 떠올릴 수 있는 것은 메인 메모리인 램(RAM)이다.
보다 정확히 말하면 D램(D-RAM) 계열의 메모리이다.
우리가 컴퓨터를 구입할 때 CPU 다음으로 중요하게 생각하는 것 중 하나이다.
참고로 메인 메모리가 반드시 램이어야 할 이유는 없다.
따라서 메인 메모리와 램에는 등호 관계가 성립하지 않는다.
그러나 거의 모든 컴퓨터가 메인 메모리로 램을 사용하므로 메인 메모리와 램을 동일한 의미로 사용하겠다.
레지스터
레지스터들도 당연히 메모리이다. CPU 안에 내장되어 있어서 연산을 위한 저장소를 제공한다.
캐시
캐시는 D램 보다 빠른 S램(S-RAM)으로 구성하는데, 램이라는 단어는 메인 메모리를 의미하는 용도로 사용되므로 캐시 메모리는 그냥 캐시라고 표현한다. 캐시는 CPU와 램 사이에서 중간 저장소 역할을 하는 메모리이다. 그리고 요즘은 캐시가 CPU에 내장되어 있다고 표현하기도 하는데 캐시 메모리는 원래 CPU의 일부로 존재하는 메모리 개념이 아니다. CPU에 근접해 있는 메모리 개념이다. CPU의 일부로 존재하는 메모리는 레지스터이다. 다시 정리하면 캐시는 CPU에 가장 근접해 있는 메모리이다. 따라서 캐시 메모리는 CPU를 디자인하는 과정에서 함께 디자인되어 하나로 제품화되는 것이 요즘 추세라고 표현하는 것이 좋을 듯하다.
하드디스크와 이외의 저장 장치들
하드디스크도 당연히 메모리이다.
하드디스크는 크고 작은 파일들을 저장하기 위한 용도로도 사용되지만, 프로그램 실행에 있어서도 중요한 의미를 지닌다. 그밖에 SD 카드, CD-ROM과 같은 I/O 장치들도 메모리에 해당한다.
프로그래머가 개발하는 데 있어서 항상 염두에 두어야 하는 가장 중요한 요소는 메모리이다. 이것을 풀어서 말하면 다음과 같다. “프로그래머는 레지스터, 캐시, 메인 메모리, 하드디스크뿐만 아니라 그 밖의 I/O 장치들과의 입/출력 타이밍 및 대기 시간 등을 가장 중요한 요소로 생각하고 항상 고민해야 한다.”
메모리 계층 구조
일반적으로 메모리를 이해하려 할 때 하드디스크는 저장, 메인 메모리는 실행이라는 관점으로 이해를 한다.
실행이라는 관점은 메모리 관리 관점이고 저장은 파일 시스템이다. 즉 둘은 완전히 다르다.
어떤 메모리를 바라볼 때 저장과 실행 두 관점 모두 살펴보면 좋다. 메인 메모리와 하드디스크는 완전히 동떨어진 게 아니다.
프로그램이 실행되는 동안에 메모리가 하는 역할은 데이터의 입력 및 출력이다.
따라서 기본적인 역할은 모든 메모리가 동일하다. 그 대상이 레지스터이건, 하드디스크이건 모두가 동일하다.
그렇다면 어떠한 부분에 있어서 차이를 보이는가?
가장 큰 차이점은 CPU를 기준으로 얼마나 멀리 떨어져 있느냐이다.
레지스터는 CPU에 가깝다 못해 CPU안에 존재하는 메모리이다.
그다음으로 가까이 있는 것은 캐시 메모리이고 그다음이 메인 메모리이다. 가장 멀리에 있는 것은 하드디스크다.
CPU와 가까이에 있을수록 빠르고 멀리 있을수록 속도가 느리다.
가상 메모리(Virtual Memory)
"메인 메모리는 512MB인데 어떻게 프로세스에 4GB가 할당되어 프로그램이 실행되는 것인가?"
하나의 프로그램을 돌리는데 CPU에서 필요한 메모리 공간이 2GB라 가정하자.
그런데 메인 메모리가 가지고 있는 메모리 공간은 256M 밖에 없다.
그래서 이러한 상황을 해결하기 위해 하드 디스크를 확장해서 쓴다.
하드 디스크를 충분히 이용할 수 있지만 속도가 느리다는 단점이 있다.
정리하면 메인 메모리가 부족하면 부족한 부분을 하드 디스크를 가져다가 쓰면 된다.
그래서 하드 디스크까지 메인 메모리를 확장해서 메모리 공간을 넓히는 것을 가리켜 가상 메모리 기법이라고 한다.
물리 주소(Physical Address)
범용 디스크는 하드디스크가 존재한다.
따라서 Windows 운영체제에서부터 각종 소프트웨어를 하드디스크에 저장해 놓고, 전원이 인가되면 저장된 소프트웨어를 기반으로 동작하게 된다. 반대로 임베디드 시스템은 하드디스크가 없다. 하드디스크가 없으니 가장 기본이 되는 운영체제도 저장되어 있지 않을 것이고 때문에 전원을 넣는다고 해서 동작될 리 만무하다.
메인 메모리인 램(RAM)에다 저장해 놓으면 어떻겠는가? 이것이 하나의 해결책이 될 수 있다.
그러나 램에 저장된 데이터는 공급되던 전원이 중단되면 사라지기 때문에 시스템을 동작하기 위해서는 전원을 인가할 때마다 매번 운영체제를 다시 로딩해야만 한다. 궁극적인 해결책이 될 수 없다. 필자가 개발하는 환경에서는 이러한 임베디드 시스템의 문제점을 플래시 메모리로 보완하였다.(플래시 메모리가 범용 컴퓨터의 하드디스크 역할을 대신하였다고 생각하면 된다.) 즉 플래시 메모리에 데이터를 저장해 놓고 전원이 인가되면 램에서 데이터가 이동하도록 디자인하였다. 그런데 이 데이터라는 것은 컴파일이 완료된 운영체제와 그 운영체제를 바탕으로 동작하는 프로그램을 총칭하는 것이다.
임베디드 시스템의 프로그램 동작은 다음과 같은 형태로 이뤄진다.
물리적 주소 지정을 하게 되면 CPU 입장에서는 접근 가능한 주소의 범위가 제한된다.
이것은 프로그래머가 할당할 수 있는 주소 범위가 제한적이라는 뜻도 된다.
이렇게 주소의 범위가 제한되면 , 프로그래머는 주소 범위를 넘어서지 않도록 주의를 기울이며 개발에 임해야 한다.
일반적으로 주소 범위의 제한 없이 프로그래밍을 해 온 여러분들은 이러한 문제를 고민해 본 적이 없을 것이다.
주소의 범위에 제한이 생긴다는 것은 프로그램 개발에 있어서 엄청난 제약사항으로 작용한다.
지금까지 설명한 물리적 주소 지정은 우리가 쉽게 이해할 수 있는 메모리 구조이다.
메인 메모리 크기가 16MB 이면 이 범위 안에서 운영체제와 프로그램을 로딩하고 프로그램 실행 과정에서 메모리를 할당해야만 한다.
가상 주소(Virtual Address) 시스템 1
32비트 시스템에서 프로세스 생성 시 4GB의 메모리를 할당받을 수 있다.
그러나 메인 메모리의 크기는 여기에 턱없이 부족하다.
따라서 4GB는 실제 존재하지 않는 가상의 주소라는 결론부터 내릴 수 있다.
이렇게 가상의 주소를 지정하는 것을 가리켜 가상 주소 지정(Virtual Addressing)이라 하며, 가상 주소 지정을 통해서 할당받게 되는 4GB를 가리켜 가상 메모리 공간이라 한다. 메인 메모리는 늘려봐야 4GB 밖에 되지 않는데(물론 늘어나겠지만), 둘 이상의 프로세스에게도 각각 4GB 메모리 공간 할당이 가능하다.
무슨 요술이라도 부리는 것인가? 내면을 들여다보면 요술도 뭐도 아니다. 그저 하나의 기술에 지나지 않는다.
상황은 이렇게 시작이 된다. 하드디스크가 80GB이다. 비록 느리지만 애도 쓸만하다.
툭 터놓고 이야기해서 메인 메모리의 역할을 하드디스크라 해서 못하라는 법은 없다. 그저 좀 느릴 뿐이다.
자! 조금 느린 하드디스크의 여유 공간이 수십 기가바이트나 되니깐 둘 이상의 프로세스에게 4GB씩 메모리 공간을 할당해 준다고 해서 문제 될 것은 없다. 단 두 가지만 고려해 준다면 말이다.
우선 두가지 문제를 얘기하기 전에 아래 내용을 살펴보자.
운영체제에서는 프로세스를 생성할 때마다 4GB 메모리 공간을 할당한다.
프로세스별로 4GB라는 건 프로세스라는 것 자체가 개발자가 짠 프로그램도 있지만 커널 코드도 있어야 한다.
대표적인 예로 내가 짠 프로그램에서 시스템 콜을 호출할 때 커널 오브젝트와 관련된 시스템 콜을 호출하면 커널 모드로 바뀌어서 커널 코드가 실행이 돼야 한다. 즉 운영체제의 코드가 실행되기 위한 메모리 공간도 필요하다. 그래서 프로세스 4GB 중에 프로그램에 2GB 커널 코드에 2GB가 할당된다고 해보자.
그러면 프로그램의 2GB 내에 프로그램 크기는 미리 할당이 돼야 한다.
프로그램 크기가 500MB라 하면 2GB - 500MB를 프로그램을 실행했을 때 활용할 수 있다.
가상 주소라는 건 메인 메모리(RAM)에 중심을 둔다. 실질적인 주소는 RAM에만 할당이 된다는 관점이다.
하드 디스크까지 메모리 영역을 확장했지만 이 하드 디스크 공간을 실질적인 물리 주소로 바라보지 않는다.
여기서 얘기하는 물리 주소는 RAM이라는 메모리 공간을 말한다.
즉 RAM이라는 메모리 공간이 256M 있다고 하면 0 ~ 256M 번지까지 할당할 수 있는 RAM 만을 물리 주소라 한다. 그럼 가상 주소라는 거는 하드 디스크까지 영역을 확장했을 때 + 알파로 얻게 되는 메모리 주소값을 가리켜 가상 주소라고 한다.
정리하면
- 가상 메모리(가상 주소)는 운영체제가 물리적 메모리(물리 주소)와 디스크를 사용하여 프로세스에 더 큰 메모리 공간을 제공하는 기술이다.
- 물리적 메모리가 부족할 경우, 운영체제는 디스크의 일부를 사용하여 가상 메모리의 일부를 저장한다. 하지만, 가상 메모리가 물리적 메모리 + 디스크 그 자체라는 의미보다는, 운영체제가 물리적 메모리와 디스크를 활용해서 프로세스가 필요한 메모리 공간을 효율적으로 관리하는 방식이라고 이해하는 게 정확하다.
선 할당으로 인한 부담 해결책
- CPU를 손님 MMU를 주인으로 생각해 보자.
- 실제 물리 메모리의 크기는 256M이지만 CPU는 2GB 메모리 공간이 있다고 가정하고 0 ~ 2GB - 1 번지까지 메모리에 접근을 하려 한다.
- 그래서 CPU는 MMU에 1GB 번지 주소에 있는 데이터를 달라고 요청을 한다. 그럼 MMU는 실제로 그 데이터를 가져다가 CPU에 준다. 마치 그 주소 영역에 데이터가 있는 것처럼 가져다가 주는 중계 역할을 한다.(CPU는 실제 그 주소 영역에 데이터가 있다고 인식을 한다)
- MMU는 16KB 밖에 존재하지 않는 메모리를 64KB가 존재하는 것처럼 CPU가 느끼도록 컨트롤하는 역할을 한다. (물론 32비트 시스템에서는 4GB의 메모리가 존재하는 것처럼 느끼게 한다.) 위 그림에서 MMU를 CPU와 독립적인 하드웨어로 표시해 뒀지만, 실제로는 CPU와 함께 하나로 패키징 되는 장치다. 이 장치가 어떻게 동작하는지 살펴보자. CPU가 메모리로 직접 접근하지 않고 MMU를 통해서 요청을 한다.
- "MMU야 1K 번지를 시작으로 20바이트를 할당하련다."
- 이러한 요청을 받은 MMU는 고민도 없이, 메인 메모리에서 아직 사용되지 않는 메모리 블록 하나를 골라서 할당을 한다.
- 그다음 두 번째 요청으로 36k 번지부터 20바이트 할당을 요청한다. 그러면 MMU는 실제 36k 번지에 20바이트를 할당하는 게 아니라 순차적으로 이전에 할당된 메모리 블록 다음 메모리 블록에 20바이트를 할당한다.
- 그림을 보면 가상 메모리 관점에서는 0 ~ 4K , 36K ~ 40K이지만 실제 물리적인 주소를 보면 0 ~ 4K, 4K ~ 8K가 된다.
- 그럼 CPU가 36K 번지에 20바이트를 할당한 다음에 36K 번지에 있는 데이터를 달라고 요청을 하면 MMU는 36K 번지를 물리주소 어디에 할당을 했는지 찾아야 한다. 즉 CPU가 가상주소로 접근을 하면 MMU는 그것을 물리 주소로 바꿔서 메인 메모리에 있는 데이터를 가져다가 CPU에 준다.
가상 메모리를 프로그래머 관점이다라고 보면 안 된다.
CPU 관점이라고 봐야 한다. CPU도 메모리를 바라보는 관점이 개발자가 바라보는 관점과 같다
가상 메모리의 블록 단위를 페이지라 하고 물리 메모리의 블록 단위를 페이지 프레임이라고 한다.
페이지와 페이지 프레임의 크기는 일치한다.
그 이유는 페이지 단위로 데이터를 물리 메모리에 할당하고 페이지 단위로 데이터를 해지하기 때문이다.
하드디스크의 일부까지 메인 메모리로 확대한 것이 가상 메모리다.
하지만 실질적인 물리 메모리는 RAM에 국한된다. 만약 단순히 RAM부터 하드디스크 일부까지 2GB를 확장해 버리면 RAM에 접근할 때는 빨라지고 하드디스크 일부에 접근할 때는 느려지는 문제가 발생한다. 그래서 하드디스크와 RAM의 관계를 캐시 관계로 구성을 했다. RAM도 캐시가 될 수 있다. 실제로 하드디스크에는 프로그램에 할당된 2GB의 메모리 공간이 존재한다. spatial locality와 temporal locality에 의해서 블록 단위로 CPU가 필요한걸 RAM에다가 가져다 놓고 실행을 시킨다. 이것이 바로 가상 메모리의 개념이다.
- RAM에 4 ~ 8K 할당 요청이 새로 왔는데 RAM이 꽉 찬 상황이다. 그래서 RAM의 일부를 빼야 한다.
- 가장 사용빈도가 낮은 것을 하드디스크에 저장한다. 여기서 오래된 것을 8 ~ 12K라고 하겠다.
- 그러면 하드디스크에 8 ~ 12K를 할당하고 기존 RAM 영역에는 4 ~ 8K가 할당이 된다.
- CPU가 8 ~ 12K에 해당하는 메모리 공간을 다시 요구한다.
- 그러면 다시 RAM에서 가장 사용빈도가 낮은 메모리 블록을 찾는다.
- 0 ~ 4K가 가장 낮다고 하면 0 ~ 4K를 하드디스크에 store 하고 그 영역에 8 ~ 12K를 load 한다.
그러면 실행 중인 프로세스에 할당된 공간이 2GB라고 하면 하드디스크에 파일로 저장한다.
이렇게 프로세스의 메모리 공간 확장을 위해서 필요한 파일을 가리켜 스왑파일이라고 한다.
즉 스왑파일이라는 건 한마디로 보따리라고 보면 된다.
보따리에서 요구하는 것을 RAM에 올려주고 RAM에서 불필요하다고 하면 다시 보따리에 저장한다.
둘 이상의 프로세스와 가상 메모리
프로세스 별로 4GB를 할당해줘야 한다.
그러면 3개의 프로세스가 생성되면 12GB의 메모리 공간 할당이 이루어져야 한다.
가능한 이유는 각각의 스왑 파일을 별도로 하드 디스크에 저장하기 때문이다.
그래서 현재 A 프로세스가 실행 중이다라고 하면 RAM은 A 프로세스와 일치되어 메모리 공간을 구성한다.
그러다가 A 프로세스에서 B 프로세스로 넘어오면 RAM은 B 프로세스와 일치되어 메모리 공간을 형성하고 작업을 진행한다. C 프로세스도 마찬가지이다. 위와 같이 RAM이 프로세스의 스왑 파일마다 일치되게 바뀌는 것도 컨텍스트 스위칭의 범주에 포함된다.
'운영체제 > 뇌를 자극하는 윈도우즈 시스템 프로그래밍' 카테고리의 다른 글
뇌를 자극하는 윈도우즈 시스템 프로그래밍 19장 (2) | 2024.09.22 |
---|---|
뇌를 자극하는 윈도우즈 시스템 프로그래밍 18장 (0) | 2024.09.22 |
뇌를 자극하는 윈도우즈 시스템 프로그래밍 15장 (0) | 2024.09.21 |
뇌를 자극하는 윈도우즈 시스템 프로그래밍 14장 (0) | 2024.09.21 |
뇌를 자극하는 윈도우즈 시스템 프로그래밍 13장 (1) | 2024.09.21 |