In Veritate Libertas

The Restricted
Section

A collection of spells,
experiments, and forbidden knowledge.

Study/[ OS ] | 2026. 7. 15. 00:01

#11 주소 변환(Address Translation)

728x90

가상 주소는 어떻게 물리 주소가 되는 거야? — 주소 변환의 시작

메모리를 가상화한다는 건 결국 OS가 프로세스한테 "너만의 메모리 공간이 있어"라고 착각시키는 거였잖아. 근데 이 착각을 실제로 만들어내려면, 프로세스가 쓰는 가상 주소를 진짜 물리 메모리 주소로 바꿔주는 하드웨어 장치가 필요해. 그게 오늘 다룰 주소 변환이야.


왜 하필 이런 방식으로 가상화할까

메모리 가상화는 효율성(Efficiency), 제어성(Controllability), 유연성(Flexibility) 세 가지를 다 잡아야 해. 그래서 CPU 스케줄링에서 이미 나왔던 LDE(Limited Direct Execution)랑 비슷한 전략을 써.

LDE를 짧게 복습하면, 프로그램을 하드웨어에서 직접 돌리다가 디스크 I/O를 요청하거나 더 많은 시스템 자원이 필요한 특정 시점에만 OS가 끼어드는 방식이야. 메모리도 똑같아 — 대부분은 하드웨어가 알아서 처리하고, 꼭 필요한 순간에만 OS가 개입해. 이게 왜 중요하냐면, 메모리 접근마다 OS가 매번 소프트웨어로 개입하면 너무 느려지거든. 그래서 하드웨어 지원을 받아서 가상 주소(virtual address, 논리 주소라고도 해)를 물리 주소(physical address)로 바꾸는 주소 변환 기법을 쓰는 거야.


프로세스는 어떻게 "이 메모리는 내 거야"라고 착각할까

주소 변환은 CPU가 들고 있는 가상 주소를 DRAM에 있는 진짜 메모리 주소로 바꿔주는 하드웨어 지원을 말해. '주소 재배치(relocation)'라고도 불러 — 같은 말이야.

이 변환 덕분에 OS는 각 프로세스한테 "너는 0번지부터 시작하는 네 전용 메모리를 쓰고 있어"라고 믿게 만들 수 있어. 실제로는 여러 프로세스가 물리 메모리 여기저기에 흩어져서 자리를 잡고 있는데도 말이야.

여러 프로세스가 각자 자기만의 4GB짜리 주소 공간을 갖고 있다고 착각하지만, 실제로는 훨씬 작은 물리 DRAM 안에 서로 다른 위치로 나뉘어 배치되는 그림을 보면 이게 확 와닿아.

각 프로세스는 자기가 0번지부터 시작하는 걸로 알고 있지만, 실제로는 물리 메모리의 전혀 다른 위치에 자리 잡고 있어. 이 간극을 메워주는 게 지금부터 볼 base·bound 레지스터야.


Base 레지스터랑 Bound 레지스터

주소 변환을 하려면 CPU에 하드웨어 레지스터 2개가 필요해.

  • base 레지스터: 가상 주소 공간이 실제 메모리 어디에 재배치됐는지, 그 시작 지점을 가리켜
  • bound 레지스터: 가상 주소 공간의 크기를 나타내 (limit 레지스터라고도 불러)

여기서 하나 확실히 짚고 갈 게 있는데, base·bound 레지스터는 DRAM이 아니라 CPU 안에 있는 아주 작고 빠른 저장 공간이야. DRAM은 우리가 흔히 말하는 그 '메모리'고, 레지스터는 CPU 코어 바로 옆에 붙어있는 완전히 다른 하드웨어야. 만약 이 레지스터가 DRAM 안에 있었다면, 주소를 변환하려고 레지스터 값을 읽는 것 자체가 또 다른 메모리 접근이 돼버려서 모순이 생겨. 매 메모리 접근마다 즉시 참조할 수 있어야 하니까 CPU에 딱 붙어있는 거야.

구체적인 숫자로 보면 감이 더 잘 와. 가상 주소 공간 크기가 16KB인 프로세스가 있다고 하면, bound 레지스터에는 16KB가 들어가. 그리고 이 프로세스를 물리 메모리 32KB 지점부터 배치하기로 했다면, base 레지스터에는 32KB가 들어가.

이 두 레지스터만 있으면 물리 메모리 원하는 위치에 가상 주소 공간을 자유롭게 배치할 수 있고, 프로세스는 자기 주소 공간에 접근하는 것처럼 동작하게 돼.


동적 재배치 (Dynamic Relocation)

base·bound 레지스터를 이용해서 하드웨어가 직접 주소를 변환해주는 방식을 동적 재배치라고 불러.

프로그램 실행이 시작되면 OS가 이 프로세스를 물리 메모리 어디에 로드할지 결정해. 그리고 base 레지스터에 그 시작 값을 넣어. 그러면 변환 공식은 이렇게 돼.

 
physical address = virtual address + base

근데 여기서 아무 가상 주소나 다 허용하면 안 돼. 반드시 이 범위 안에 있어야 해.

 
0 <= virtual address < bound

이 두 가지 — 덧셈으로 변환하고, 범위를 체크하는 것 — 덕분에 주소 변환도 되고 동시에 프로세스 보호도 같이 챙길 수 있어. 만약 이 범위를 벗어나는 접근이 들어오면, 하드웨어가 바로 잡아내고 OS가 개입해서 처리해.

여기서 중요한 전제 조건 하나: base·bound 레지스터 값은 오직 OS만 바꿀 수 있어. 일반 프로세스가 마음대로 이 값을 조작할 수 있다면 다른 프로세스 메모리 영역을 마음대로 침범할 수 있게 되니까, 이 값을 건드리는 명령어는 커널 모드에서만 실행 가능해.

 

 

면접 포인트 ( •̀ ω •́ )✧

Q. 동적 재배치 기술에 대해 설명해 주세요.

더보기

base·bound 레지스터를 이용해서 CPU가 실행 중에 가상 주소를 물리 주소로 바꾸는 하드웨어 기법입니다. 물리 주소 = 가상 주소 + base 공식으로 변환하고, 0 <= 가상 주소 < bound 조건으로 범위를 체크해서 프로세스가 자기 영역 밖으로 못 나가게 막습니다. base·bound 값은 OS만 수정할 수 있어서, 이 메커니즘이 주소 변환이랑 메모리 보호를 동시에 해결합니다.


MMU — 주소 변환을 실제로 처리하는 하드웨어

MMU(Memory Management Unit)는 CPU가 메모리에 접근할 때 주소 변환을 도와주는 하드웨어 장치야. 가상 주소를 실제 주소로 바꿔주는 역할을 담당해.

가상 주소가 들어오면 MMU는 base 레지스터 값을 더해서 물리 주소 후보를 만들고, 이 값이 bound(limit) 레지스터 범위 안에 있는지 검사해. 범위 안이면 실제 주소로 내보내고, 범위를 벗어나면 예외(exception)를 발생시켜서 다른 프로세스 영역으로 접근하는 걸 막아줘.

정리하면, MMU는 가상 주소와 base 레지스터를 더한 값이 bound(=limit) 레지스터 범위 안에 들어가면 그대로 물리 주소로 내보내고, 범위를 벗어나면 예외 처리를 시켜.

 

 

 

면접 포인트 ( •̀ ω •́ )✧

Q. MMU에 대해 설명해 주세요.

더보기

MMU는 Memory Management Unit의 약자로, CPU가 메모리에 접근할 때 가상 주소를 물리 주소로 변환해주는 하드웨어 장치입니다. base 레지스터를 더해서 물리 주소를 계산하고, bound 레지스터로 범위를 검사해서 유효하면 물리 주소를 반환하고 벗어나면 예외를 발생시켜서 다른 프로세스의 메모리를 침범하지 못하게 막는 역할을 합니다.


이 모든 걸 실제로 관리하는 건 결국 OS

지금까지는 하드웨어가 주소 변환에서 뭘 하는지 봤으니까, 이제 OS가 어느 시점에 개입해야 하는지 볼 차례야. base·bound 레지스터를 실제로 쓰려면 OS가 반드시 관여해야 하는 상황이 네 가지 있어.

  1. 프로세스가 생성될 때 — 물리 메모리에 여유 공간이 있는지 찾아야 해
  2. 프로세스가 종료될 때 — 쓰던 메모리 공간을 다른 프로세스가 쓸 수 있게 되돌려놔야 해
  3. Context Switch가 발생할 때 — base·bound 레지스터 정보를 저장하고 복원해야 해
  4. 그 외 예외가 발생했을 때 — 호출할 핸들러나 함수를 미리 준비해둬야 해

프로세스가 시작될 때 — Free List

프로세스가 새로 생기면, OS는 새로운 주소 공간을 넣을 여유 공간을 물리 메모리에서 찾아야 해. 이때 쓰는 게 free list야. 사용되지 않는 물리 메모리 범위 목록, 그러니까 지금 비어있는 공간 목록이야.

예를 들어 free list가 16KB랑 48KB 지점을 가리키고 있다면, 그 위치가 지금 비어있는 여유 공간이라는 뜻이야. OS는 물리 메모리 어디에 빈 공간이 있는지 계속 추적하고 있어야 새 프로세스가 들어올 자리를 바로 찾아줄 수 있어.

 

프로세스가 종료될 때 — Free List에 반납

프로세스가 종료되면, OS는 그 프로세스가 쓰던 공간을 다시 free list에 올려놔야 해. Process A가 exit되면, 그 자리를 나중에 다른 프로세스가 쓸 수 있게 free list에 추가해주는 거야.

 

Context Switch가 발생할 때 — PCB에 저장

Context Switch가 일어나면, OS는 base랑 bound 레지스터 값을 동시에 저장하고 복원해야 해. 이 값들은 프로세스마다 process structure 또는 PCB(프로세스 제어 블록)에 저장돼서 관리돼.

예를 들어 Process A가 실행되던 중에 Context Switching이 일어나면, Process A의 base·bound 값을 A의 PCB에 저장해. 그 다음 Process B가 실행되다가 다시 전환될 때, PCB에 저장해뒀던 Process A의 값을 다시 꺼내서 A를 이어서 실행시켜.

 

 

면접 포인트 ( •̀ ω •́ )✧

Q. OS가 개입해야 하는 상황들에 대해서 설명해 주세요.

더보기

크게 세 가지입니다. 프로세스가 생성될 때는 free list를 확인해서 새 주소 공간이 들어갈 물리 메모리 여유 공간을 찾아야 하고, 프로세스가 종료될 때는 쓰던 공간을 free list에 반납해야 합니다. 그리고 Context Switch가 발생할 때는 현재 프로세스의 base·bound 레지스터 값을 PCB에 저장하고, 다음에 실행될 프로세스의 값을 PCB에서 꺼내 레지스터에 복원해야 합니다. 이 세 가지 외의 예외 상황을 위한 핸들러도 OS가 미리 준비해둬야 합니다.


꼭 기억할 것 하나만 꼽으면: 주소 변환의 핵심은 "덧셈 한 번 + 범위 체크 한 번"이고, 이 단순한 연산이 하드웨어 속도로 실행되기 때문에 매 메모리 접근마다 OS가 개입 안 해도 가상화가 가능해지는 거야. base·bound 방식은 구현이 단순하다는 장점이 있는데, 사실 치명적인 약점도 하나 있어 — 프로세스의 힙이랑 스택 사이에 있는 비어있는 공간까지도 통째로 물리 메모리에 자리를 차지해버리거든. 이 낭비를 어떻게 줄이는지가 다음 글에서 다룰 세그멘테이션(Segmentation)의 핵심 동기야.

 

728x90

'Study > [ OS ]' 카테고리의 다른 글

#13 페이징 (Paging)  (0) 2026.07.15
#12 Segmentation  (0) 2026.07.15
#10 주소 공간과 가상 메모리  (0) 2026.07.06
#09 교착상태 (DeadLock)  (0) 2026.07.06
#08 동기화(뮤텍스, 세마포어, 스핀락)  (0) 2026.07.02
흐이서

흐이서

Writer

공순이 흐이서