293. 세그멘테이션 (Segmentation)
핵심 인사이트 (3줄 요약)
- 본질: 세그멘테이션 (Segmentation)은 프로그램을 기계적으로 똑같은 크기로 써는 페이징과 달리, 코드, 데이터, 스택 등 논리적인 의미와 역할에 따라 서로 다른 크기의 덩어리(세그먼트)로 잘라서 관리하는 기법이다.
- 가치: 의미 단위로 묶여 있기 때문에 특정 세그먼트(예: 코드 영역) 전체를 '읽기 전용'으로 묶거나 여러 프로그램이 함께 쓰는 '공유' 설정이 페이징에 비해 압도적으로 직관적이고 편리하다.
- 융합: 세그먼트들의 크기가 제각각이라 메모리에 넣고 빼기를 반복하면 빈 공간이 지저분하게 남는 외부 단편화가 발생하며, 현대 OS에서는 이를 해결하기 위해 페이징과 혼용하는 하이브리드 방식을 사용한다.
Ⅰ. 개요 및 필요성
-
개념: 가상 메모리를 고정된 물리적 크기가 아닌, 사용자 관점의 논리적 단위인 '세그먼트'로 나누는 방식이다. 각 세그먼트는 고유한 이름(번호)과 길이를 가진다.
-
필요성: 페이징은 하드웨어가 관리하기엔 편하지만, 프로그래머 입장에서는 내가 짠 함수나 배열이 페이지 경계에 걸쳐 쪼개지는 것이 매우 불편하다. 세그멘테이션은 "코드는 코드끼리, 데이터는 데이터끼리" 덩어리째 관리함으로써 보안 권한 설정과 메모리 공유를 훨씬 인간 친화적으로 만들어준다.
-
💡 비유: 돼지 한 마리를 도축할 때 페이징이 무조건 가로세로 5cm 깍두기 모양으로 썰어버리는(기계적) 것이라면, 세그멘테이션은 삼겹살, 목살, 갈비 등 부위별(논리적 의미)로 크기가 다르게 덩어리째 썰어내는 방식입니다.
-
등장 배경: 1960년대 초창기 메인프레임 환경에서 프로그램의 구조적 보호를 위해 도입되었다. 이후 인텔 x86 아키텍처의 핵심 메모리 모델로 자리 잡았으나, 단편화 문제로 인해 현대에는 페이징의 보조 수단으로 역할이 축소되었다.
┌──────────────────────────────────────────────────────────────┐
│ 세그멘테이션의 논리적 분할 구조 도식 │
├──────────────────────────────────────────────────────────────┤
│ │
│ [ 논리적 주소 공간 ] [ 물리적 메모리 ] │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Segment 0 (Code)│ ──────────────▶│ │ │
│ │ (10KB) │ │ Segment 1 │ │
│ ├──────────────────┤ ├──────────────────┤ │
│ │ Segment 1 (Data)│ ──────────────▶│ Segment 0 │ │
│ │ (4KB) │ ├──────────────────┤ │
│ ├──────────────────┤ │ (빈 공간) │ │
│ │ Segment 2 (Stack) ├──────────────────┤ │
│ │ (8KB) │ ──────────────▶│ Segment 2 │ │
│ └──────────────────┘ └──────────────────┘ │
│ │
│ * 특징: 세그먼트마다 크기가 제각각이며, 실제 램에서도 가변적임. │
└──────────────────────────────────────────────────────────────┘
- 📢 섹션 요약 비유: 책을 장(Chapter) 단위로 묶어놨기 때문에, "1장은 모두가 같이 돌려봐라(공유)", "2장은 절대 연필로 낙서하지 마라(보호)"라고 통제하기가 아주 수월한 도서 관리 시스템입니다.
Ⅱ. 아키텍처 및 핵심 원리
세그먼트 테이블 (Segment Table)과 주소 변환
가상 주소는 (세그먼트 번호 s, 오프셋 d)로 구성된다.
- Base: 세그먼트가 시작되는 실제 물리 주소.
- Limit: 세그먼트의 실제 길이.
- 변환 과정: MMU는 세그먼트 번호를 보고 테이블에서 Base와 Limit을 찾는다. 만약 오프셋(d)이 Limit보다 크면 Segmentation Fault를 발생시키고, 정상이면
Base + d로 실제 주소를 계산한다.
외부 단편화 (External Fragmentation)의 저주
세그멘테이션의 가장 큰 적은 단편화다.
-
10MB, 5MB, 20MB 등 제각각인 조각들을 넣고 빼다 보면, 메모리 중간중간에 2MB, 3MB짜리 작은 구멍들이 숭숭 뚫린다.
-
전체 빈 공간은 50MB인데, 정작 30MB짜리 세그먼트가 들어오려 하면 "연속된 30MB 공간이 없어서" 실행하지 못하는 낭패가 벌어진다.
-
📢 섹션 요약 비유: 크기가 제각각인 테트리스 블록이 계속 내려오는데 한 줄이 다 차도 안 없어지는 끔찍한 게임과 같습니다. 결국 중간에 빈칸이 숭숭 뚫린 채로 화면 꼭대기까지 블록이 차올라 게임 오버(메모리 부족)가 되어버립니다.
Ⅲ. 비교 및 연결
페이징 vs 세그멘테이션 결정적 차이
| 비교 항목 | 페이징 (Paging) | 세그멘테이션 (Segmentation) |
|---|---|---|
| 분할 단위 | 고정 크기 (기계적) | 가변 크기 (논리적) |
| 단편화 | 내부 단편화 발생 | 외부 단편화 발생 |
| 장점 | 메모리 활용 효율 최상 | 보호 및 공유가 매우 용이 |
| 주소 변환 | 페이지 테이블 인덱싱 | Base + Offset 연산 |
| 현대 표준 | 메인 아키텍처 | 보조 아키텍처 (Hybrid) |
하이브리드 방식: Paged Segmentation
현대 대부분의 CPU(x86-64 등)는 두 방식을 섞어 쓴다.
- 프로그램을 논리적인 세그먼트로 먼저 나눈다 (보안/공유 목적).
- 각 세그먼트 내부를 다시 고정된 페이지로 잘게 쪼갠다 (단편화 해결 목적). 이렇게 하면 프로그래머는 세그먼트의 편리함을 누리고, 하드웨어는 페이징의 효율성을 챙기는 윈-윈(Win-win)이 가능해진다.
- 📢 섹션 요약 비유: 요즘 아파트는 거실, 안방(세그먼트)으로 구획을 나누되, 바닥 공사는 규격화된 타일(페이지)을 여러 장 깔아서 마무리하는 것과 같습니다. 공간의 의미도 살리고 시공(관리) 효율도 잡는 방식입니다.
Ⅳ. 실무 적용 및 기술사 판단
실무 시나리오
-
C언어의 Segmentation Fault 원인 분석 포인터 연산 실수로 내가 할당받은 배열의 범위를 벗어나 접근했을 때 발생하는 에러. MMU가 세그먼트 테이블의 Limit 값을 체크하다가 "어? 너 100바이트만 쓰기로 해놓고 왜 101바이트를 찔러?"라고 판단하여 프로그램을 강제 종료시킨 것이다. 이는 단순한 버그를 넘어 타 프로세스의 영역을 침범하는 해킹 시도를 하드웨어 수준에서 차단한 보안 승리의 현장이다.
-
공유 라이브러리 (Shared Library, .so/.dll)의 효율적 관리 수십 개의 프로그램이 동일한 '표준 C 라이브러리' 코드를 사용할 때. 세그멘테이션 덕분에 이 라이브러리 코드를 하나의 세그먼트로 묶고 'Read-Only & Shared' 속성을 부여하여 램에 딱 한 번만 올리고 모든 프로세스가 돌려쓰게 함으로써 막대한 램 용량을 절약할 수 있다.
도입 체크리스트
- 기술적: 외부 단편화로 인한 압축(Compaction) 비용이 시스템 응답성에 치명적이지 않은가?
- 보안적: 코드, 데이터, 스택 세그먼트의 권한을 분리하여 '데이터 영역 실행 방지(DEP)' 기능을 활성화했는가?
안티패턴
-
단편화 해결을 위한 잦은 메모리 압축(Compaction): 조각난 빈 공간을 모으겠다고 실행 중인 프로그램들을 램 여기저기로 옮기는 행위. 이 작업 동안 시스템 전체가 일시 정지(Stop-the-world)되므로, 리얼타임 시스템에서는 절대 금물이다. 이럴 땐 차라리 페이징으로 갈아타야 한다.
-
📢 섹션 요약 비유: 이삿짐을 쌀 때 가구 크기에 맞춰 박스를 주문 제작(세그멘테이션)하면 보관은 좋지만 나중에 차에 실을 때 공간이 빕니다. 잦은 짐 재배치는 이삿짐센터 직원(CPU)을 쓰러지게 만드니, 차라리 표준 박스(페이징)를 쓰는 게 낫습니다.
Ⅴ. 기대효과 및 결론
정량/정성 기대효과
| 구분 | 효과 | 설명 |
|---|---|---|
| 논리적 보호 | 최상 | 함수/데이터 단위로 권한을 부여해 해킹 차단 |
| 메모리 공유 | 매우 용이 | 라이브러리 공유를 통해 램 사용량 절감 |
| 프로그래밍 | 직관적 | 개발자가 이해하는 메모리 구조와 일치 |
| 공간 효율 | 낮음 | 외부 단편화로 인한 '죽은 공간' 발생 위험 |
미래 전망
- 객체 지향 하드웨어: 미래의 CPU는 단순한 바이트 주소가 아니라 '객체(Object)' 자체를 세그먼트로 인식하여, 하드웨어가 직접 메모리 안전(Memory Safety)을 검사하는 방향으로 진화할 것이다 (예: CHERI 아키텍처).
- 보안 격리의 핵심: 가상화 기술이 심화되면서, 특정 보안 연산만을 위한 초소형 세그먼트(Enclave)를 물리적으로 격리하는 기술이 더욱 중요해지고 있다.
결론
세그멘테이션은 "컴퓨터의 언어가 아닌 인간의 언어(논리)"로 메모리를 바라보려는 인류의 시도였다. 비록 물리적인 공간 낭비라는 한계에 부딪혀 페이징에게 주도권을 내주었지만, 보안과 공유라는 측면에서 세그멘테이션이 제시한 '의미 단위 관리' 철학은 현대 하이브리드 아키텍처 속에 녹아들어 시스템의 안전을 지키는 가장 강력한 방어선으로 남아있다.
- 📢 섹션 요약 비유: 세그멘테이션은 옷을 '머리, 가슴, 배' 부위별로 예쁘게 오려내는 재단사와 같습니다. 기계적으로 자르는 것보다 훨씬 맵시 있고 관리하기 좋지만, 남은 자투리 천(외부 단편화)이 많이 생기는 것을 감수해야 하는 예술적인 메모리 관리법입니다.
📌 관련 개념 맵
| 개념 명칭 | 관계 및 시너지 설명 |
|---|---|
| 페이징 | 세그멘테이션의 외부 단편화 문제를 해결하기 위해 현대 OS가 선택한 파트너. |
| 세그먼트 테이블 | 각 세그먼트의 시작 주소(Base)와 크기(Limit)를 기록한 비밀 지도. |
| 외부 단편화 | 세그멘테이션의 최대 단점이자, 연속된 빈 공간이 없어 할당에 실패하는 현상. |
| Segfault | 세그먼트가 허용된 범위를 넘어섰을 때 MMU가 날리는 하드웨어의 엄중한 경고. |
| 공유 세그먼트 | 여러 프로세스가 하나의 코드 덩어리를 돌려쓰게 해주는 효율적인 메모리 절약 기술. |
👶 어린이를 위한 3줄 비유 설명
- 세그멘테이션은 스케치북을 자를 때 깍두기 모양으로 막 자르는 게 아니라, 머리, 가슴, 배처럼 부위별로 예쁘게 오려내는 거예요.
- 부위별로 나뉘어 있으니까 "머리 부분은 절대 색칠하지 마!"라고 규칙을 정하기가 아주 편해요!
- 하지만 오려낸 조각들의 크기가 다 달라서, 나중에 빈 상자에 다시 집어넣을 때 크기가 안 맞아서 버려지는 공간이 생기는 게 유일한 단점이랍니다!