이전 장에서 프로세스의 상태에 대해 자세하게 알아봤습니다. 그리고 프로세스는 독립된 메모리 공간이라고 설명했었습니다. 간단하게 저번에 학습한 내용을 복습해보면 프로세스의 상태는 생성 -> 준비 -> 대기 -> 실행 -> 종료 -> 좀비 -> 해제 순으로 진행이 되어지며, 스케쥴러를 통해 프로세스의 실행 순서를 결정하게 되어집니다. 실행 순서를 나타내는 방식으로는 FSFC 먼저 들어온 친구부터 처리하는 기법, 우선순위 우선순위가 높은거 부터 처리하는 기법, RR 순차적으로 돌면서 처리하는 기법(순차적은 원형입니다.) SFJ 짧은 시간이 걸릴거 같은거 부터 처리하는 기법, CFS CPU가 가장 적게 쓴거 부터 처리하는 기법등이 존재합니다. 핵심은 모든 스케쥴러는 최초 1회는 FSFC으로 동작을 하게 되고, RR을 기반으로 파생이 되어 만들어졌습니다. 더 나아가면 윈도우가 쓰는 스케쥴러 기법과 리눅스가 사용하는 스케쥴러의 차이가 있다는 사실을 알게 되었죠(깊게는 조사는 안했습니다.) 지금까지 학습을 했지만, 의문이 드는 건, 프로세스가 메모리라 했는데 실질적으로 메모리는 어떻게 관리가 되어질까요? 이번에 알아봅시다.
메모리 관리?
프로세스라는 장치를 실제로 우리가 보지는 못했습니다. 사실 프로세스는 물리적인 장치가 아닙니다. 정확히 말하면 논리적인 실행단위라 할 수 있습니다. 독립된 메모리 또한 커널이 구성한 가상 주소 공간에 불과합니다. 기억을 끄집어서 프로세스는 힙, 스택, 데이터, 코드로 구성이 되어 있다고 했죠. 즉, 이들도 가상의 메모리라는 것을 알 수 있습니다.
그렇다면 커널은 이러한 메모리들을 어떻게 관리를 하는걸까요?
다음과 같은 역할을 가진다고 합니다.
1. 가상 주소 공간을 만든다 2. 페이지 테이블을 생성한다
3. 실제 물리 메모리는 접근할 때만 할당된다 4. Buddy System은 RAM을 관리하는 기본 allocator 5. Slab Allocator는 '커널 내부 객체' 전용
1 -> 2는 생성단계
3은 실행중 반복적으로 발생
4,5는 백그라운드 메모리 관리자라고 합니다. 여기서 우리가 집중적으로 학습할 부분은 1,2,3번입니다. 4,5번은 추후에 학습하도록 하겠습니다. (지금 공부하면 오히려 헷갈리짐)
그렇다면 가상 주소 공간을 만든다는게 무슨말일까요?
프로세스도 가상인데 가상의 가상이라 뭔가 이상합니다. 어디부터 잘못 이해 한걸까요?
사실 아는 잘못알고 있는 정보라고 합니다. 프로세스는 가상 공간이 아닌 논리적인 실행단위입니다. 이를 다시말하면 설계도면을 그린다고 하면 된다고 합니다. 예를 들어, 아파트를 짓는다고 생각해봅시다. 아파트에는 다양한 동 호수가 존재합니다. 동 호수는 설계도면을 그릴때 이미 반영이 되어있죠. 이거와 비슷하다고 보시면 됩니다. 우리는 아파트의 동 호수를 보고 어느 위치에 있는지 알 수 가 있죠. 하지만 실제 땅 주소는 000동 000호가 아닙니다. 그렇다고 해서 아파트에서 그러한 정보까지는 알지는 못하죠.
가상 주소 공간을 제공한다는 것은,아파트에 동·호수를 배정하듯, "이 프로세스는 이 논리적 구조로 메모리를 사용할 것이다" 라고
설계도를 미리 확보해두는 행위라고 이해할 수 있습니다.

* MMU: CPU 안에 들어있는 하드웨어 회로로, 가상 주소를 물리 주소로 실시간 변환하는 장치
대략적으로 요런 그림을 그릴 수 있습니다. 실제로는 프로세스는 실제 주소를 알 수 없습니다.
여기서 의문이 드는 사실이 있습니다. 프로세스는 가상 공간에서 실행됩니다. 즉, 프로세스 입장에서 메모리는 0x0000부터
시작하는 독립된 가상 주소 공간입니다. 하지만 CPU와 RAM은 이 주소를 그대로 사용할 수 없습니다. 왜냐하면 CPU는 물리 주소만 이해하는 하드웨어이기 때문입니다. 따라서 운영체제는 프로세스를 생성할 때 해당 프로세스가 사용할 가상 주소 공간을 설계도처럼 미리 구성합니다. 그러나 이 공간은 아직 실제 메모리를 차지하지 않습니다. 메모리에 접근하는 순간, MMU가 페이지 테이블을 조회하여 가상 주소를 실제 RAM의 물리 주소로 변환합니다.
MMU에는 다양한 역할이 존재합니다. 여기서 학습할 역할은 주소 변환입니다. 생각을 해보면 이것이 왜 필요할지에 대해 생각해봅시다.
MMU는 어떻게 주소를 변환할까?
다음과 같은 과정을 거친다고 합니다.
1. CPU가 가상 주소를 전달합니다.
2. MMU가 가상 주소를 둘로 분리합니다.
3. TLB에서 매핑을 먼저 찾습니다
4. 페이지 테이블을 조회합니다.
5. 물리주소를 생성합니다.
6. 권한 및 존재 여부를 조사합니다.
7. 최종적으로 RAM에 등록합니다.
이들을 자세하게 알아보기 전에 왜 이렇게 까지 하나 알아봅시다.
가장 중요한 이유는 가상주소(VA)를 보고 어느 프로세스에서 왔는지 알 수 없습니다. CPU가 가상 주소로 전달을 한들 그 주소가 어느 프로세스 소유인지 모르기 때문에 아직까지는 의미가 없습니다. 즉 아직 까지는 관리가 쉽지 않다는 거죠. 그렇다면, 이걸 어떻게 하면 관리를 할수 있을까요?
일단 CPU에서 가상주소를 MMU로 전달합니다. 가상주소를 전달할때 위에서 어느 프로세스 출신인지는 모른다고 했죠. 그렇다는건 동일한 가상 주소가 존재할 수 도 있다는 뜻입니다. 그렇다고 해서 이것을 바로 물리 주소로 변환을 시키면 안됩니다. 가장 중요한 사실은 어느 프로세스(물리)로 변환을 시켜야 할지 모른다는 뜻이 됩니다. 그러면 어떻게 구분할까요?
이것을 해결하기 위해 페이징이라는것으로 해결할 수 있다고 합니다. 물론 아주 간단하게 생각해서 인덱싱으로 처리하면 되지 않을까 생각할 수 있습니다. 과연 가능할까요? 불가능하다고 합니다. 그 이유는 너무 광범위해서 인덱스로만 가지고 처리하는 것이 불가능하다고 합니다. 게다가 성능도 최악이라고 하니 페이징이라는것을 통해 처리할 수 밖에 없다고 합니다.
그렇다면, 어떻게 페이징이라는것은 위치 보장과 성능을 보장할 수 있을까요?
그냥 물리 주소를 바로 쓰면 안되나? 어떻게든 되지 않을까? 등등 여러가지 방법을 생각할 수 있습니다.
이것을 하는 목적중 하나는 보안입니다. 즉, 물리적인 주소를 노출이 되어지는 순간 이 물리적인 주소로 접근이 굉장히 쉬워질겁니다. 왜냐하면 실제 주소를 알고 있으니까요. 예시를 들어보겠습니다. 가끔 자동차를 보면 전화번호가 적혀 있을때 가 많습니다. 이렇게 전화번호를 노출하다보면 범죄의 대상이 되기 쉽습니다. 그래서 이것을 가려서 다른 번호로 대체해서 보여줍니다. 이렇게 되면 다른 사람이 보는 번호는 실제 번호는 아니지만 그 번호로 전화를 걸 수 있게 됩니다. 여기서 핵심은 가상 전화 번호와 전화 번호 사이에 매핑관계가 되어 있을겁니다. 이것이 매핑 테이블입니다.
그렇다면 메핑 테이블로만 가지고 처리하면 되지 않을까요? 그렇게 되면 엄청난 수의 프로세스를 관리를 해야 하기 때문에 여간 쉬운 작업은 아닙니다.
그것을 해결하는 방법이 바로 페이징입니다. 페이징은 페이징 번호와 오프셋으로 구분이 되어져 있습니다.
페이징 번호야 현재 페이징이 어느 순서인지 말한것이기때문에 그리 어렵지는 않은데 오프셋은 무엇일까요?
오프셋은 가상 주소가 저장되어있는 좌표라고 합니다. 그러니까 오프셋은 그 페이징에서 정확한 위치를 뜻하는 거라고 합니다. 누누히 말하지만 물리주소랑 전혀 상관이 없습니다. 오프셋은 페이지 테이블 조회에도 사용되지 않으며, 단지 변환된 물리 프레임 시작 주소에 더해져 최종 물리 주소를 계산할 때만 사용됩니다.
중간에서 페이징처리까지 완료했고 물리 주소로 변환을 완료했다고 가정해봅시다.
그렇게 되면 위에서 본것처럼 RAM에 등록이 되어질 겁니다. 그런데 페이징이라고 하면 책을 읽는 듯이 1페이지 넘기고 2페이지 넘기고 그렇게 생각하면 안됩니다.
페이징 방법
우리가 RAM이 되었다고 가정해봅시다. RAM은 알다시피 휘발성 메모리 공간입니다. 그렇기 때문에 많은 내용을 기억할 수 없습니다. 그렇다는건 1페이지씩 기억하는게 아니라 최대한 기억을 하려고 할겁니다. (1페이지만 기억한다면 유감) 그러면 1,2,3,4페이지가 들어오고 그것을 기억하고 그 페이징을 사용하는 과정에서 페이징 교체 알고리즘이 발생하게 되어집니다. 대표적으로 FIFO, OPT, LRU, Clock등이 있다고 합니다. (시간상 내부적인건 생략)
이러한 페이징 교체 알고리즘을 활용해서 프로세스를 사용을 합니다. 그렇다면 의문이 있습니다. 프로세스 생성은 어떻게 연관이 되어질까요?
마무리
OS를 공부하면서 왜 개발을 하면서 OS가 왜 중요한지 이해를 하지 못했습니다. OS를 몰라도 개발은 충분히 할 수 있으니까요. 비록 3주간OS의 모든것을 학습한것은 아니지만, 학습을 해보니 알게더라구요. 우리가 배운 대부분의 지식들은 OS에서 넘어왔다는 사실을 알게 되었습니다. 예시로 들면 카프카에는 페이징과 오프셋이라는 개념이 들어가있습니다. 이는 OS에도 유사하게 발생했던 부분입니다. 100% 똑같다라고 말할 수 는 없겠지만 OS에 대한 지식을 각 기술에 접목을 시킨다면, 누구보다 빠르고 정확하게 이해할 수 있을거라 생각합니다.
아쉬운건 학습을 하면서 구멍이 생각보다 많았더라구요. 아직도 해결되지 않은것들이 많네요. OS에 대한 지식이 없으니 이 정도면 OS랑 친해지지 않았나 싶습니다. 다음주는 DB입니다.
'OS' 카테고리의 다른 글
| 프로세스 고도화 (0) | 2025.11.17 |
|---|---|
| [OS] 네트워크 복습 + 프로세스와 스레드 (0) | 2025.11.09 |