백엔드 면접 용어 사전
운영체제virtual memory

가상 메모리

물리 메모리보다 큰 주소 공간을 제공하는 기법. 페이지 단위로 필요한 부분만 올려 쓴다.

프로세스마다 자기만의 연속된 메모리 공간이 있는 것처럼 보여 주는 기법. 실제 물리 메모리와는 별개의 주소 체계다.

무엇을 해결하나

가상 메모리가 없다면

  • 프로그램이 물리 주소를 직접 써야 한다 → 어디에 적재될지 미리 알아야 함
  • 다른 프로세스의 메모리를 마음대로 읽고 쓸 수 있다 → 보안·안정성 붕괴
  • 물리 메모리보다 큰 프로그램을 아예 못 돌린다
  • 메모리가 조각나면 연속 공간을 못 찾는다

주소 변환

프로세스가 보는 것 (가상)          실제 (물리)
0x0000_1000  ──────────────────►  0x8A3F_2000
0x0000_2000  ──────────────────►  0x1B04_7000   ← 흩어져 있어도 무방
0x0000_3000  ──────────────────►  디스크(스왑)   ← 아예 메모리에 없을 수도

페이지 테이블이 이 대응표다. CPU의 MMU(메모리 관리 장치)가 매 접근마다 변환한다.

페이지 단위로 관리하는 이유

메모리를 고정 크기 조각(보통 4KB) 으로 나눈다.

가상 주소 0x00001234 (32비트, 페이지 4KB일 때)
┌─────────────────────┬──────────────┐
│ 페이지 번호 0x00001 │ 오프셋 0x234 │
└─────────────────────┴──────────────┘
       ↓ 페이지 테이블 조회
   프레임 번호 0x8A3F
       ↓
물리 주소 0x8A3F234        ← 오프셋은 그대로 붙인다

고정 크기라 외부 단편화가 없다. 어느 빈 프레임에든 넣을 수 있기 때문이다. (대신 마지막 페이지에 남는 내부 단편화는 생긴다.)

얻는 것들

효과어떻게
프로세스 격리각자 페이지 테이블이 달라 남의 메모리를 가리킬 수 없다
메모리보다 큰 프로그램필요한 페이지만 올리고 나머지는 디스크에(요구 페이징)
공유같은 물리 프레임을 여러 프로세스의 페이지가 가리키면 됨(공유 라이브러리)
Copy-on-Writefork() 시 복사 없이 공유하다 쓸 때만 복사
보호페이지마다 읽기/쓰기/실행 권한

Copy-on-Write가 중요한 이유

  • fork() 호출

  • 전통적으로는 부모의 메모리 전체를 복사해야 함 (수 GB면 재앙)

  • CoW: 페이지 테이블만 복사하고 모든 페이지를 "읽기 전용 공유"로 표시

  • 누군가 쓰려고 하면 그때 그 페이지만 복사

  • 대부분의 fork는 곧바로 exec 하므로 사실상 복사가 거의 안 일어난다

Redis의 백그라운드 저장(BGSAVE)이 이 원리로 동작한다 — 자식 프로세스가 스냅샷을 뜨는 동안 부모는 계속 서비스하고, 변경된 페이지만 실제 복사된다. 그래서 쓰기가 많으면 메모리 사용량이 최대 2배까지 늘 수 있다.

다단계 페이지 테이블

64비트 주소 공간 전체의 대응표를 만들면 테이블만으로 메모리가 다 찬다. 그래서 트리 구조로 나눠 실제 쓰는 부분만 만든다(x86-64는 4~5단계).

대가는 변환마다 메모리를 4번 읽어야 한다는 것 — 이 비용을 없애는 것이 TLB다.

대가

  • 변환 오버헤드 (→ TLB로 완화)
  • 페이지 폴트 시 디스크 접근이면 수만 배 느려진다
  • 스왑이 과해지면 스래싱

함께 보면 좋은 용어

노트에서 맥락과 함께 보기 — 운영체제 — 프로세스/스레드·동기화·가상메모리