우리가 사용하는 언어는 대개 인간이 읽고 쓰기 쉽도록 설계된 고급언어이다. 고급언어를 통해 소스파일을 작성하고, 큰 프로그램을 설계한다. 고급언어로 짠 코드는 우리의 언어와 비슷하게 생겼다. 근데 이게 어떻게 0과 1뿐인 메모리를 조작할 수 있는 걸까?
(방대한 내용을 공부하면서 큰 그림을 이해해보고자 작성한 글이라, 틀린 내용이 있을 수도 있습니다 !! 혹시 발견하신다면 편하게 댓글로 남겨주세요. 공부에 큰 도움이 될 것 같습니다. 🙇🏻)
개발자의 코드가 물리 메모리까지 닿는 과정
우리가 작성한 소스코드는 전처리를 거친 후에 컴파일러가 이를 어셈블리어 코드로 바꾸고, 어셈블러가 이 코드를 다시 기계어로 바꾼다(C언어 기준). 기계어로 된 소스파일은 최종적으로 링킹을 거친다. 이렇게 되면 개발자가 작성한 프로그램은 연속적인 명령어 바이트의 형태로 보조기억장치(HDD, 요즘은 SSD)에 저장된다. 이때는 윈도우로 치면 .exe 파일이 되어있다.
프로그램 로딩, 실행
어떤 .exe 실행 파일을 실행하면, 운영체제는 파일 시스템에서 해당 파일을 찾는다. (앞서 CSAPP 1장에서 훑어봤지만, 파일 시스템은 보조기억장치를 포함한 입출력장치의 추상화이다.) 그리고 해당 실행 파일의 데이터를 보조기억장치로부터 메인 메모리에 load 한다. 파일의 코드, 데이터, 리소스 등이 메인 메모리로 복사되는 과정이다. 이렇게 하는 이유는 보조기억장치에 접근하는 과정은 메인 메모리 대비 크게는 10만배 가량 느리기 때문에, 매번 보조기억장치에서 코드를 읽어오는 것은 너무 비효율적이기 때문이다. 이렇게 메인 메모리로 복사된 실행 파일은 프로세스라고 부른다.
그리고 프로세스는 각각 독립적인 가상 메모리(Virtual Memory, VM)를 할당받는다. 가상 주소 공간은 코드 영역, 데이터 영역, 스택, 힙 영역 등으로 나누어 구성되어 있다. 그리고 가상 메모리 내부의 어떤 지점은 가상 주소를 통해 지목할 수 있다. 어셈블리어 또는 C 계열 코드를 보면 알겠지만 우리는 실제 메인 메모리 내부가 어떤 구조인지를 디테일하게 고려하지 않는다. 그저 무언가 가상의 주소 공간을 상상하고, 이 안에서의 주소만 잘 짚어낼 뿐이다.
CPU는 메인 메모리에 load된 실행파일의 명령어(기계어)를 하나씩 읽고 실행한다. 명령어 수행 과정에서 CPU는 그때그때 메인 메모리의 특정 공간에 접근할 필요가 있는데, 이때 가상 주소를 통해 메인 메모리를 인식하고 통제한다. 예를 들어 기계어는 코드 영역에서 읽어나가고, 함수 호출 시 스택 영역, 전역 변수가 나오면 데이터 영역으로 접근한다. 이 영역 구분은 가상 주소 상에서 정의된 것이다. 그러나 가상 주소는 말 그대로 가상 메모리의 주소이고, 추상화를 넘어 실제 메인 메모리의 정확한 위치를 짚어줘야 상호작용 할 수 있다. 이때, 가상 주소과 대비되는 개념으로, 실제 메인 메모리가 갖고있는 주소를 물리 주소라고 부른다.
불완전하게나마 비유하자면, 우리가 택시에 타서 '서대문구 연희동으로 가주세요~' 라고 하는건 가상 주소를 통해 명령을 내리는 거다. 그러나 해당 지점을 정확하게, 최대한 현실과 매치되게 위도와 경도로 나타내는 것이 물리 주소이다.
가상 메모리의 정의: 가상메모리 | (2) 가상메모리 개념, 가상 주소공간
가상 메모리와 물리 메모리의 상호작용 (주소 변환)
따라서 가상 주소를 갖고 실제 메인 메모리에 접근하기 위해서는 이를 물리 주소로 변환하는 과정이 필요하다. 이 변환 과정은 MMU(Memory Management Unit)라는 CPU 칩 내부의 하드웨어를 거쳐 수행된다. CPU의 명령어 수행부는 가상 주소만 알고있고 이를 통해 명령어를 처리하면, 중간에서 MMU가 이를 받아서 물리주소로 변환한다.
이때, 가상주소와 매칭되는 물리주소를 찾기 위해서 일종의 주소록을 탐색한다. MMU는 가장 먼저 MMU 내부 혹은 MMU와 인접해 있는 TLB(Translation Lookaside Buffer)를 먼저 탐색하고, 이 안에 가상주소와 매칭되는 물리주소가 있다면 그대로 메인 메모리에 접근한다(TLB hit).
그러나 TLB 안에 매칭되는 물리주소가 없다면 메인메모리의 페이지 테이블(페이지 테이블 = PTE(Page Table Entry)의 배열) 영역에 접근하여 주소를 찾는다(TLB miss). PTE는 TLB보다 더 크고 많은 정보를 담고있는 주소록이라고 생각하면 된다. 만약 PTE에 매칭되는 주소가 있다면, 해당 물리주소를 TLB에 저장하고(최근 사용기록 저장과 같은 개념) 찾아낸 물리주소를 따라 메인 메모리에 접근한다.
Page?
마치 도량형을 통일시키듯, 시스템이 메모리 영역을 다루기 위해서도 일관된 단위가 필요한데, 그래서 제안된 것이 Page이다. 가상 메모리 주소 공간을 일정한 크기로 자르고, 그 각각을 Page로 치는 것이다. 앞선 malloc lab에서도 살핀 바 있지만 일반적으로 Page는 4kb 단위이다. 그리고 이와 같은 크기로 실제 메인 메모리를 나누어 매칭한다. 이때 메인 메모리에서의 각 조각은 Frame이라고 부른다.
즉, 개발자와 CPU는 가상메모리의 page를 바라보면서 명령을 내리고, 명령어가 동작하는 동안 시스템은 가상메모리의 Page에 매칭되는 물리메모리의 Frame을 찾기 위해 CPU는 TLB와 PTE를 탐색하는 것이다.
한편, 물리 주소를 찾았는데 해당 물리 주소가 메인메모리를 가리키고 있지 않을 수 있다. 이는 Page fault라고 부른다. DRAM 캐시 미스인 경우이다. 해당 영역을 사용할 것이라고 예측하여 Page in을 해놓지 못했거나, 사용을 안할 줄알고 보조기억장치로 Page out 해놓은 것이다. 이는 보조기억장치에 접근하여 해당 영역을 메인메모리로 올려놓는 오버헤드를 발생시킨다.
- 이는 프로세스들로 하여금 제한적인 실제 RAM 용량보다 더 큰 메모리 공간을 활용할 수 있도록 하는 과정에서 생기는 시행착오라고 볼 수 있다.
- 각 프로세스는 실제 RAM 용량보다 더 큰 범위의 가상메모리 공간을 할당받을 수 있다. 이는 프로세스에서 자주, 또는 앞으로 사용하게 될 메모리 공간은 메인 메모리에 load 해놓고, 그렇지 않은 부분은 보조기억장치의 스왑 영역에 보관해둠으로써 가능하다. 그리고 상황마다 필요한 부분을 보조기억장치와 RAM 간에 swap해줌으로써, 결과적으로는 메인 메모리 용량보다 훨씬 큰 메모리 영역을 다루는 효과를 누리게 되는 것이다.
- 따라서, 가상 메모리는 물리적인 메인 메모리뿐만 아니라 보조기억장치의 스왑 영역까지 메인 메모리처럼 보이도록 하는 일종의 착시(?)효과로 실제 메인 메모리보다 훨씬 큰 가상의 메인 메모리를 구현해낸다.
근데, 지금까지의 내용을 보면 떠오르는 키워드가 하나 있다: 캐시(Cache)!
- 보조기억장치의 실행파일을 메인 메모리로 load하는 과정, 가상 주소를 물리 주소로 변환하는 과정, 페이지 스왑을 통해 한정된 메모리를 더 넓게 쓰는 기법 등에는 캐싱 아이디어가 녹아있다.
- 데이터를 처리하거나 저장하는 단계를 계층적으로 구성하여, 비교적 빠른 과정을 더 가까이에 두고 자주 사용하는 것들을 올려놓음으로써 효율성을 극대화하는 것이다. (PTE에서 자주 쓰이는 주소변환 목록은 TLB에 로드, 프로세스에서 자주 쓰일 법한 데이터는 HDD에서 메인 메모리에 로드)
운영체제, VM System
그럼 이러한 과정들도 결국 어떠한 시스템이 관장하는 것일텐데, 개발자들이 프로그램을 짤 때마다 이 모든걸 함께 설계하진 않는다. 그럼 어떤 주체가 이 모든 과정을 진두지휘하는 것일까?
- 그 주체는 바로 운영체제(OS)이다. 실제 물리적인 반도체인 하드웨어 layer와 우리가 모니터를 통해 접근하는 User layer 사이에는 운영체제 layer가 있다. 즉, 인간과 하드웨어 가운데에서 중재자 역할을 해주는 것이다.
- 운영체제 내부에서 하드웨어와 직접 소통하는 핵심 영역은 커널 영역이라고 하는데, 커널 영역 내에 VM System이 정의되어 있다. VM System이 수많은 프로세스들에 가상메모리를 할당하고, 각 가상메모리 공간이 서로를 침범하지 않도록 하며, 물리 메모리를 더 효율적으로 활용할 수 있도록 관리하는 역할을 맡는다.
'Computer Science > 컴퓨터 구조 (Computer Architecture)' 카테고리의 다른 글
가상메모리 | (3) 세그멘테이션, 페이징 (0) | 2023.11.15 |
---|---|
가상메모리 | (2) 가상메모리 개념, 가상 주소공간 (0) | 2023.11.15 |
동적 메모리 할당 | Malloc Lab | (4) 할당기 배치 전략 개선 (next fit) (0) | 2023.11.14 |
동적 메모리 할당 | Malloc Lab | (3) 기초적인 할당기 작동 원리, 구현 (0) | 2023.11.12 |
동적 메모리 할당 | Malloc Lab | (2) 과제 소개 (0) | 2023.11.11 |