연속 메모리 할당 (Contiguous Memory Allocation)
핵심 인사이트 (3줄 요약)
- 본질: 연속 메모리 할당(Contiguous Memory Allocation)은 하나의 프로세스가 요구하는 크기 전체를 물리적 메모리의 인접한 공간(연속된 주소)에 끊어짐 없이 통째로 배정하는 가장 고전적이고 직관적인 메모리 관리 기법이다.
- 가치: 주소 변환 하드웨어(MMU, 베이스 레지스터 단 1개)가 매우 단순하여 실행 속도가 극도로 빠르며, 메모리 보호 로직(한계 레지스터 1개) 구현이 직관적이다.
- 융합: 하지만 메모리에 빈 공간이 생겼다 채워졌다를 반복하면서 발생하는 치명적인 외부 단편화(External Fragmentation) 문제로 인해 한계에 봉착했고, 이를 해결하기 위해 메모리를 잘게 조각내는 비연속 할당(페이징, 세그멘테이션) 아키텍처로 진화하는 역사적 트리거가 되었다.
Ⅰ. 개요 및 필요성 (Context & Necessity)
-
개념: 연속 메모리 할당은 실행될 프로그램의 논리적 주소 공간 전체가 물리 메모리의 한 구역에 '연속적으로(Contiguously)' 담겨야 한다는 원칙이다. 즉, 100MB짜리 프로그램이라면 메모리 1000번지부터 100MB+1000번지까지 하나의 통짜 덩어리로 들어가야 한다.
-
필요성: 초기 컴퓨터는 메모리 관리 장치(MMU) 같은 하드웨어가 빈약했다. CPU가 순차적인 명령어를 읽어들이기 위해서는, 그 명령어들이 물리 메모리 상에서도 순서대로 예쁘게 나열되어 있어야만 했다. 복잡하게 흩어진 주소를 매번 찾아가는 것은 불가능에 가까웠으므로, OS는 단순히 빈 공간을 찾아 통째로 밀어 넣는 방식을 택할 수밖에 없었다.
-
💡 비유: 연속 메모리 할당은 극장에서 **"우리 일행 5명은 무조건 나란히 붙어 있는 5연석 좌석에만 앉겠습니다!"**라고 고집하는 진상 관객과 같다. 앞줄에 2자리, 뒷줄에 3자리가 비어 있어 총 5자리가 남아있더라도, 연속되지 않으면 영화를 보지 않고 집에 가버린다.
-
등장 배경 및 딜레마:
- 초기 단일 프로그래밍: 컴퓨터에 OS 하나, 유저 프로그램 하나만 존재했다. 그냥 메모리 시작점에 OS 넣고, 그 뒤에 사용자 프로그램을 통째로 넣으면 끝이었다. (매우 평화로움)
- 다중 프로그래밍의 등장: 프로그램 A, B, C가 메모리에 올라오고 빠져나가기를 반복하자, 메모리 중간중간에 이빨 빠진 듯한 빈 공간(Hole)들이 생기기 시작했다.
- 외부 단편화(External Fragmentation)의 공포: 남아있는 빈 공간을 다 합치면 100MB인데, 죄다 흩어져 있어서 50MB짜리 새 프로그램을 적재할 수 없는 비극적 상황이 연출되었다. 이것이 컴퓨터 공학 역사상 가장 유명한 메모리 낭비 문제다.
┌───────────────────────────────────────────────────────────────────────┐
│ 연속 메모리 할당의 한계: 외부 단편화 (External Frag) │
├───────────────────────────────────────────────────────────────────────┤
│ │
│ [ 초기 상태 ] │
│ ┌─────┬──────────┬──────────┬──────────┬─────┐ │
│ │ OS │ 프로세스 A │ 프로세스 B │ 프로세스 C │ 빈 공간│ │
│ │ 10M │ 20MB │ 30MB │ 40MB │ 20M │ │
│ └─────┴──────────┴──────────┴──────────┴─────┘ │
│ │
│ [ 프로세스 B 종료 후 30MB 구멍 발생 ] │
│ ┌─────┬──────────┬──────────┬──────────┬─────┐ │
│ │ OS │ 프로세스 A │ ▒ 빈구멍 ▒ │ 프로세스 C │ 빈 공간│ │
│ │ 10M │ 20MB │ ▒ 30MB ▒ │ 40MB │ 20M │ │
│ └─────┴──────────┴──────────┴──────────┴─────┘ │
│ ※ 새로운 40MB짜리 프로세스 D가 실행을 요청한다면? │
│ => 전체 빈 공간은 50MB(30+20)지만, '연속'되지 않아서 D는 실행 거부됨!│
└───────────────────────────────────────────────────────────────────────┘
[다이어그램 해설] 이 그림은 연속 할당의 맹점을 완벽히 보여준다. 프로세스 D 입장에서는 억울하다. 시스템 전체에 50MB의 램이 남아돌지만, 쪼개져 있다는 이유 하나만으로 램이 꽉 찬 것(OOM)과 동일한 오류를 뱉어낸다. OS는 이 구멍(Hole)들을 관리하기 위해 자유 공간 리스트(Free list)를 유지하며 낑낑대야 했다.
- 📢 섹션 요약 비유: 주차장에 차를 댈 때, 캠핑카(대형 프로세스) 한 대를 대기 위해 일반 차 3대가 나란히 빠진 연속된 3칸의 자리가 나올 때까지 밖에서 무한정 대기해야 하는 비효율적인 주차 시스템입니다.
Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)
구성 요소
| 요소명 | 역할 | 내부 동작 | 관련 기술 | 비유 |
|---|---|---|---|---|
| OS 커널 영역 | 운영체제 시스템 보호 | 보통 메모리의 최하단(0번지) 또는 최상단에 상주하여 보호받음 | Interrupt Vector | 호텔의 카운터 및 스태프 공간 |
| 사용자 프로세스 영역 | 일반 앱이 올라가는 공간 | 빈 구멍(Hole)을 찾아 프로세스 덩어리를 통째로 적재 | Memory Allocation | 손님들이 머무는 객실들 |
| 자유 공간 리스트 (Free List) | 빈 구멍들의 크기와 주소 기록 | 프로세스 종료 시 인접한 구멍과 병합(Coalescing) 작업 수행 | Linked List | 카운터의 빈방 장부 |
| 단일 베이스 레지스터 | 동적 주소 변환 | 논리 주소 + Base = 물리 주소 연산 1회 수행 | MMU Hardware | 손님에게 주는 첫 번째 방 번호표 |
| 단일 한계 레지스터 | 연속된 공간의 끝점 보호 | 논리 주소가 크기(Limit)를 넘는지 검사 | Memory Protection | 방을 벗어나지 못하게 하는 울타리 |
하드웨어 주소 변환 아키텍처의 단순성
연속 메모리 할당의 유일한이자 가장 강력한 장점은 런타임 성능이다. 메모리가 하나의 통나무처럼 이어져 있기 때문에, 복잡한 테이블(Page Table)을 뒤져볼 필요 없이 덧셈 한 번으로 물리 주소가 튀어나온다.
┌─────────────────────────────────────────────────────────────────────────┐
│ 연속 메모리 할당 환경에서의 하드웨어 주소 변환 로직 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ [ CPU ] │
│ │ 논리 주소 (ex: 오프셋 500) │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 논리 주소 < 한계? │◀── 한계 레지스터 (Limit=1000) │
│ └────────┬────────┘ │
│ │ (Yes) 통과 │
│ ▼ │
│ ┌─────────────────┐ │
│ │ 논리 주소 + 베이스 │◀── 베이스 레지스터 (Base=3000) │
│ └────────┬────────┘ │
│ │ │
│ ▼ │
│ [ 물리 메모리 3500번지 ] (1클럭 사이클 내 초고속 접근) │
└─────────────────────────────────────────────────────────────────────────┘
[다이어그램 해설] 구조가 너무나 단순하여 전용 칩셋 구성비용이 극도로 싸고 처리가 빛의 속도다. CPU가 "500번지 데이터 줘"라고 하면, 하드웨어는 "크기(1000) 안 넘었네? 시작점이 3000이니까 더해서 3500번지!"라고 1나노초 만에 결정한다. 페이징 기법에서는 이 과정에서 메모리에 있는 페이지 테이블을 또 읽어와야 하는 성능 패널티(TLB로 극복하지만)가 발생하는데, 연속 할당은 그런 오버헤드가 제로다.
외부 단편화 해결책: 압축 (Compaction)
흩어진 빈 공간 때문에 프로그램이 실행되지 않는 사태를 막기 위해, OS는 최후의 수단으로 **메모리 압축(Compaction, 일명 쓰레기 수집)**을 시도한다.
-
흩어져 있는 모든 프로세스를 한쪽 벽으로 밀어버리고, 나머지 빈 공간들을 반대쪽으로 몰아서 하나의 거대한 구멍(Big Hole)을 만드는 작업이다.
-
치명적 문제: 16GB 메모리를 가진 컴퓨터에서 10GB의 데이터를 한쪽으로 복사(Copy)하는 것은 수천만 번의 읽기/쓰기 사이클을 동반한다. 압축이 진행되는 동안 컴퓨터는 문자 그대로 **정지(Freeze)**해버린다. 현대 컴퓨터에서는 절대 용납될 수 없는 비용이다.
-
📢 섹션 요약 비유: 책장에 책들이 드문드문 꽂혀있어 두꺼운 백과사전이 안 들어갈 때, 기존 책들을 전부 밀어서 한쪽으로 빽빽하게 재정렬(압축)한 뒤에야 남은 빈칸에 꽂는 엄청난 노동의 과정입니다.
Ⅲ. 융합 비교 및 다각도 분석
비교 1: 연속 할당 (Contiguous) vs 비연속 할당 (Non-contiguous, 페이징)
운영체제 메모리 관리의 패러다임을 바꾼 역사적 비교점이다.
| 비교 항목 | 연속 메모리 할당 | 비연속 할당 (페이징 / 세그멘테이션) |
|---|---|---|
| 할당 형태 | 프로세스를 1개의 통짜 블록으로 적재 | 프로세스를 4KB 등 여러 개의 조각으로 찢어서 적재 |
| 단편화 문제 | 외부 단편화 (최악) 발생 | 외부 단편화 없음 (다만 미세한 내부 단편화 존재) |
| 메모리 압축 | 주기적으로 압축(Compaction) 필요 (서버 멈춤) | 압축이 전혀 필요 없음 |
| 하드웨어 복잡도 | 레지스터 2개면 끝남 (매우 단순, 초고속) | 복잡한 페이지 테이블과 TLB 캐시 필수 (복잡) |
| 공유(Sharing) | 다른 프로세스와 코드 일부 공유가 매우 까다로움 | 특정 페이지만 공유 테이블로 매핑하면 쉽게 공유 가능 |
분할 방식에 따른 연속 할당의 종류
연속 할당 기법 자체도 공간을 어떻게 나눌 것인가에 따라 두 가지로 파생된다. (다음 키워드에서 상세히 다룸)
- 고정 분할 (Fixed Partition): 미리 메모리를 10MB, 20MB 단위로 쪼개놓고 덩치에 맞는 방에 밀어 넣는 방식. (내부 단편화 발생)
- 가변 분할 (Variable Partition): 프로그램 크기만큼 그때그때 잘라서 할당하는 방식. (외부 단편화 발생)
┌──────────┬────────────┬────────────┬──────────────────────┐
│ 방식 │ 단편화 종류 │ 낭비 정도 │ 관리 난이도 │
├──────────┼────────────┼────────────┼──────────────────────┤
│ 연속 고정 │ 내부 단편화 │ 심함 │ 매우 쉬움 │
│ 연속 가변 │ 외부 단편화 │ 심함 (압축필요)│ 복잡함 │
│ 비연속 페이징│ 미세 내부단편 │ 거의 없음 │ 매우 복잡함 │
└──────────┴────────────┴────────────┴──────────────────────┘
[매트릭스 해설] 컴퓨터 과학에서 메모리 관리는 '단편화(Fragmentation)와의 전쟁'이었다. 고정 분할은 방이 커서 남는 내부 단편화에 시달렸고, 가변 분할은 방들이 찢어져서 외부 단편화에 시달렸다. 결국 인류는 이 "연속성"이라는 고집 자체를 버리고, 프로세스를 모래알처럼 잘게 부숴버리는 비연속 할당(페이징)으로 도망침으로써 이 전쟁을 끝냈다.
- 📢 섹션 요약 비유: 퍼즐 맞추기를 할 때, 1번부터 100번 조각을 무조건 일렬로만 놔야 한다는 규칙(연속 할당) 때문에 책상에 자리가 남아도 퍼즐을 못 맞추다가, 그냥 뿔뿔이 흩어놔도 그림이 보이게 뇌파(MMU)를 개조한 것(비연속 할당)과 같습니다.
Ⅳ. 실무 적용 및 기술사적 판단 (Strategy & Decision)
실무 시나리오: 임베디드 및 RTOS (Real-Time OS) 환경
- 상황: 미사일 요격 시스템이나 자동차 브레이크 제어(ABS)를 담당하는 초정밀 실시간 운영체제(RTOS)를 설계한다.
- 페이징의 기피:
- 범용 OS(Windows, Linux)처럼 페이징을 쓰면 페이지 폴트가 발생할 때 하드디스크를 읽어오는 지연(수십 ms)이 생긴다.
- 브레이크를 밟았는데 페이지 폴트 때문에 0.1초 늦게 작동하면 운전자는 사망한다. 즉, 시간 예측 가능성(Determinism)이 파괴된다.
- 연속 할당의 부활:
- 이런 하드코어 실시간 시스템에서는 외부 단편화를 감수하더라도, 주소 변환 오버헤드나 지연이 절대 0인 연속 메모리 할당(또는 물리 메모리 직접 매핑) 방식을 채택한다.
- 모든 태스크를 부팅 시점에 1개의 연속된 블록에 못 박아버리고, 실행 중에는 동적 할당 자체를 금지해 단편화를 원천 봉쇄하는 코딩 규약(MISRA C 등)을 사용한다.
연속 할당의 현대적 잔재 (Huge Pages)
-
현대 리눅스 서버에서도 연속 할당의 철학이 일부 부활했다. DB 서버의 경우 4KB 페이지 테이블이 너무 커져서 TLB 캐시 미스가 잦아지는 문제가 발생했다.
-
이를 해결하기 위해 2MB 또는 1GB짜리 **거대 페이지(Huge Pages)**를 연속적으로 할당하는 옵션을 켠다. 연속된 큰 덩어리를 줌으로써 하드웨어 매핑 오버헤드를 연속 할당 시절처럼 비약적으로 낮추는 융합 전략이다.
-
📢 섹션 요약 비유: 대중교통(페이징)이 아무리 효율적이라도, 환자 생명이 위급한 구급차(RTOS)는 신호등도 안 걸리고 직진만 할 수 있는 전용 중앙차로(연속 할당)가 반드시 필요한 것과 같은 이치입니다.
Ⅴ. 기대효과 및 결론 (Future & Standard)
정량/정성 기대효과
| 구분 | 내용 |
|---|---|
| 속도 극대화 | 주소 변환이 덧셈 1회로 끝나, 메모리 접근(Memory Access) 레이턴시가 이론상 최저치 달성 |
| 하드웨어 절감 | 복잡한 페이징 회로나 TLB 메모리 없이 베이스/리미트 레지스터만으로 구현 가능 (제조 단가 하락) |
| 예측 가능성 | 메모리 상에 순차적으로 존재하므로 캐시 라인(Cache Line) 적중률이 극도로 높아 순차 읽기에 유리 |
결론 및 미래 전망
연속 메모리 할당 (Contiguous Memory Allocation)은 다중 프로그래밍 시대에 '외부 단편화'라는 거대한 암초를 만나 범용 OS 시장에서는 퇴출당한 낡은 기술이다. 빈 공간을 병합하고 압축하는 비용은 한정된 자원 아래서 무한에 가까운 오버헤드를 낳았다. 하지만 이 기술이 지닌 '절대적인 단순함과 빠름'은 시간 결정성(Determinism)이 생명인 RTOS 분야나 커널 내부의 슬랩 할당기(Slab Allocator), 데이터베이스의 거대 페이지(Huge Page) 최적화 기법 등에서 여전히 그 유전자를 이어가며, 페이징 아키텍처의 복잡성을 보완하는 강력한 무기로 생존해 있다.
- 📢 섹션 요약 비유: 커다란 장작을 쪼개지 않고 통째로 아궁이에 넣으면(연속 할당) 화력(속도)은 엄청나지만 아궁이 입구(메모리 공간)에 맞추기 어려웠던 과거의 투박하고 강력한 불피우기 방식입니다.
📌 관련 개념 맵 (Knowledge Graph)
- 외부 단편화 (External Fragmentation) | 전체 빈 공간은 충분하나 조각나 있어서 큰 프로세스를 연속 할당할 수 없는 문제
- 메모리 압축 (Compaction) | 외부 단편화를 해결하기 위해 프로세스들을 한쪽으로 복사해 밀어붙이는 비용이 막심한 작업
- 페이징 (Paging) | 연속 할당의 외부 단편화 문제를 해결하기 위해 메모리를 블록 단위로 잘게 찢은 비연속 할당 기술
- 동적 메모리 할당 알고리즘 | 가변 분할의 연속 할당 시, 흩어진 구멍들 중 어디에 넣을지 고르는 방법 (First-fit, Best-fit 등)
- 베이스 레지스터 (Base Register) | 프로세스가 위치한 연속된 메모리 공간의 맨 앞쪽 출발선 주소를 기억하는 하드웨어
👶 어린이를 위한 3줄 비유 설명
- 연속 메모리 할당이 뭔가요? 영화관에 친구 5명이 놀러 갔을 때, 무조건 5자리가 나란히 쭉 붙어있는 곳에만 앉겠다고 고집 부리는 방법이에요.
- 왜 그렇게 하나요? 중간에 모르는 사람이 껴있지 않아서 팝콘을 전달하거나 귓속말을 하기가 엄청나게 빠르고 편하거든요.
- 무엇이 문제인가요? 극장에 빈자리가 총 10개나 남아있어도, 다 1자리씩 흩어져 있으면 5명이 나란히 앉을 수 없어서 영화를 못 보고 집에 돌아가야 하는 짜증 나는 일이 발생한답니다.