| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | |||||
| 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| 10 | 11 | 12 | 13 | 14 | 15 | 16 |
| 17 | 18 | 19 | 20 | 21 | 22 | 23 |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 |
| 31 |
- IAM Federation
- python
- operating system
- reversing
- AWS 인프라 분석
- AWS
- AWS 인프라 아키텍처
- terraform
- 리버싱
- dreamhack
- C
- 드림핵
- Amazon S3
- AWS Active Directory
- 운영체제
- 네트워크
- AWS 침해 사고 사례 분석
- AWS 보안 사고 사례 모음
- programmers
- AWS 사고 사례 분석
- AWS 침해사고 사례 분석
- TryHackMe
- AWS 아키텍처 분석
- AWS 3 Tier Architecture
- 프로그래머스
- AWS IAM Role
- reversing.kr
- 침입 차단 시스템(IPS)
- network
- AWS 보안 아키텍처 분석
- Today
- Total
lhywk 님의 블로그
[운영체제 OS] Memory Management 본문
1. 메모리 관리의 개요 및 요구조건
1-1 메모리 관리의 정의
다중 프로그래밍 환경에서 한정된 주기억장치(RAM)를 여러 프로세스에 동적으로 할당하고 배치하는 운영체제의 기능이.
1-2 메모리 관리의 5가지 요구조건
- 재배치 (Relocation): 프로세스가 메모리 내 어느 위치에 있더라도 정상 실행되도록 지원.
- 보호 (Protection): 타 프로세스나 OS 영역 침범 방지.
- 공유 (Sharing): 공통 코드/데이터를 여러 프로세스가 함께 사용하도록 허용.
- 논리적 구성 (Logical Organization): 프로그램을 모듈/세그먼트 단위로 관리 및 맵핑.
- 물리적 구성 (Physical Organization): RAM과 디스크 간의 데이터 이동(스와핑 등) 관리.
2. 연속 메모리 할당 기법
프로그램 전체가 하나의 커다란 공간에 연속적으로 할당되는 것이다.
2-1 고정 분할 (Fixed Partitioning)
메모리를 미리 고정된 크기로 나누어 두는 방식이다.
프로세스가 분할 영역보다 작으면, 남는 공간이 발생. 이를 내부 단편화라고 한다.

1. 균등 분할 (Equal-size Partitioning)
운영체제를 제외한 모든 메모리 파티션의 크기가 동일하다.
- 장점: 관리가 매우 간단하다.
- 단점: 심각한 내부 단편화를 유발. 예를 들어, 8MB 크기의 파티션에 1MB짜리 프로세스를 넣으면 7MB의 공간이 그대로 낭비. 또한, 파티션 크기(8MB)보다 조금이라도 큰 프로세스는 아예 실행될 수 없다.
2. 비균등 분할 (Unequal-size Partitioning)
메모리 파티션들의 크기가 서로 다르다.
- 장점: 작은 프로세스는 작은 파티션에, 큰 프로세스는 큰 파티션에 할당하여 메모리 낭비를 줄일 수 있다.
- 단점: 여전히 내부 단편화 문제가 발생. 예를 들어, 위 그림 (b)에서 9MB 크기의 프로세스는 12MB 파티션에 들어가야 하므로 3MB의 공간이 낭비. 또한, 파티션의 개수가 정해져 있어 동시에 실행할 수 있는 프로세스의 수가 제한된다.

- 파티션별 큐 (Per-Partition Queue)각 파티션마다 별도의 대기 줄을 두는 방식이다.
- 단일 큐 (Single Queue)하나의 공통된 대기 줄에 모든 프로세스를 세우는 방식. 파티션이 비면, OS는 대기 줄을 쭉 훑어보고 그 파티션에 들어갈 수 있는 가장 적합한 프로세스를 선택한다.
2-2 동적 분할 (Dynamic Partitioning)
프로세스가 필요한 만큼만 딱 맞춰서 메모리를 할당한다.

- (a) → (d) 프로세스 할당: 처음에는 텅 빈 메모리(a)에 프로세스 1, 2, 3이 순서대로 들어온다. 각 프로세스는 자신이 요청한 크기만큼만 정확히 할당. 이 덕분에 고정 분할의 문제였던 내부 단편화는 발생하지 않는다.
- (e) 프로세스 종료: 중간에 있던 프로세스 2가 종료되자, 그 자리가 14M 크기의 빈 공간으로 남음.
- (f) → (h) 단편화 발생: 새로운 프로세스 4(8M)가 들어오면서 14M 공간에 배치되고, 6M의 작은 조각이 남음(f). 이후 프로세스 1이 종료되고(g), 그 자리에 새 프로세스 2(14M)가 들어오면서 또 다른 6M 조각이 남음(h).
최종 상태 (h)를 보면, 비어있는 공간이 6M, 6M, 4M로 총 16M나 남아있다. 하지만 이 공간들이 모두 분리되어 흩어져 있기 때문에, 만약 10M 크기의 새로운 프로세스가 들어오려고 해도 할당해 줄 수 없는 문제가 발생한다.
이처럼 사용 가능한 메모리 총량은 충분하지만, 그것이 연속된 공간이 아니어서 할당할 수 없는 상태를 외부 단편화라고 한다.
해결책: 집약(Compaction)을 통해 조각들을 모아야 하지만 부하가 크다.
동적 분할의 4가지 배치 알고리즘

1. 최초 적합 (First-Fit)
- 메모리의 처음부터 검색해서, 프로세스가 들어갈 수 있는 첫 번째 빈 공간에 바로 할당한다.
2. 최적 적합 (Best-Fit)
- 모든 빈 공간을 검색해서, 프로세스가 들어가기에 충분한 공간 중 가장 크기가 딱 맞는(가장 작은) 곳에 할당한다.
3. 최악 적합 (Worst-Fit)
- 모든 빈 공간을 검색해서, 프로세스를 넣을 수 있는 가장 큰 공간에 할당한다.
4. 순환 적합 (Next-Fit)
- 최초 적합과 유사하지만, 검색을 메모리 처음이 아닌 이전에 마지막으로 할당했던 위치부터 시작한다.
3. 버디 시스템 (Buddy System)
고정 분할과 동적 분할의 절충안으로, 메모리 블록을 2^k 크기로 분할하여 관리한다.

- 할당: 요청 크기에 맞는 최소 2^k 블록을 찾고, 없으면 상위 블록을 반으로 쪼개 할당한다.
- 해제(병합): 메모리 반환 시 인접한 버디 블록이 비어있으면 다시 합쳐 큰 블록을 만든다.
1. 할당 (분할) 과정
- A: 100K 요청
- 100K보다 큰 최소의 2k 크기는 128K
- 시스템은 1MB → 512K → 256K → 128K로 블록을 연속으로 분할하여 A에 할당
- 결과: [A:128K] [128K] [256K] [512K]
- B: 240K 요청
- 240K보다 큰 최소의 2k 크기는 256K
- 남아있던 256K 블록을 B에 할당
- 결과: [A:128K] [128K] [B:256K] [512K]
- C: 64K 요청
- 64K는 2k 크기이므로 바로 64K를 할당
- 남아있던 128K 블록을 64K 버디 두 개로 분할하여 하나를 C에 할당
- 결과: [A:128K] [C:64K] [64K] [B:256K] [512K]
- D: 256K 요청
- 남아있던 512K를 256K 버디 두 개로 분할하여 하나를 D에 할당
2. 반환 (병합) 과정
메모리 반환 시에는 "나의 버디도 비어있는가?"를 확인하여, 비어있다면 합치는 병합 과정이 핵심
- B 반환: 256K 공간이 비게 됨. B의 버디는 A, C 등이 차지하고 있으므로 병합은 일어나지 않는다.
- A 반환: 128K 공간이 비게 됨. A의 버디는 C가 차지하고 있으므로 병합은 일어나지 않는다.
- C 반환: 64K 공간이 비게 됨.
- C의 버디(바로 옆 64K)도 비어있으므로, 둘을 합쳐 하나의 128K 블록으로 병합
- E 반환: 128K 공간이 비게 됨
- 1단계 병합: E의 버디(바로 옆 128K)도 비어있으므로, 둘을 합쳐 하나의 256K 블록으로 병합.
- 2단계 병합: 새로 만들어진 256K 블록이 자신의 버디(B가 반환한 256K)를 확인하니 역시 비어있다. 따라서 둘을 합쳐 하나의 512K 블록으로 다시 병합.
- D 반환: 256K 공간이 비게 됨
- D의 버디(오른쪽 끝 256K)도 비어있으므로 512K 블록으로 병합.
- 새로 만들어진 512K 블록이 자신의 버디(왼쪽의 512K)를 확인하니 역시 비어있다.
- 최종적으로 두 512K 블록이 합쳐져 원래의 1MB 통 메모리로 복구.
4. 주소 변환 및 하드웨어 지원
4-1 주소의 종류
- 논리 주소 (Logical Address): CPU가 생성하며 프로세스 관점에서 0번지부터 시작하는 주소이다.
- 물리 주소 (Physical Address): 실제 메모리 칩에 접근하기 위한 주소이다.
4-2 MMU (Memory Management Unit)
실행 시간에 논리 주소를 물리 주소로 변환하는 하드웨어 장치이다.
- 베이스 레지스터 (Base Register): 시작 물리 주소 저장.
- 경계 레지스터 (Limit Register): 프로세스 크기 저장 (보호 기능).
- 계산식: 물리 주소 = 베이스 레지스터 값 + 논리주소
5. 불연속 메모리 할당 기법
5-1. 페이징 (Paging)
- 페이지 (Page): 프로세스(논리 메모리)를 나누는 고정된 크기의 조각.
- 프레임 (Frame): 주기억장치(물리 메모리)를 나누는 조각으로, 페이지와 크기가 정확히 동일.
- 페이지 테이블 (Page Table): 운영체제가 각 프로세스마다 관리하는 주소 변환용 테이블.
특징
- 외부 단편화 없음: 빈 프레임 어디든 페이지를 넣을 수 있기 때문이다.
- 내부 단편화 발생: 마지막 페이지가 꽉 차지 않을 때 발생한다.

- (a) → (d) 프로세스 적재: 처음에는 메모리가 비어있어 프로세스 A, B, C가 순서대로 들어오면서 물리적으로 연속된 빈 프레임에 차례대로 할당.
- (e) 프로세스 B 스왑 아웃 (Swap-out): 메모리 공간이 더 필요해지자, 운영체제는 중간에 있던 프로세스 B를 메모리에서 내보냄. 그 결과 프레임 4, 5, 6이 다시 사용 가능한 빈 공간이 됨.
- (f) 프로세스 D 적재: 이제 5개의 페이지로 이루어진 프로세스 D가 들어올 차례.
- 운영체제는 비어있는 프레임들을 찾아 D의 페이지들을 배치.
- D의 처음 세 페이지(D.0, D.1, D.2)는 B가 비워준 4, 5, 6번 프레임에 들어감.
- 나머지 두 페이지(D.3, D.4)는 메모리 뒷부분에 있던 다른 빈 프레임인 11, 12번에 배치.
이처럼 프로세스 D의 페이지들이 메모리 곳곳에 흩어져서(불연속적으로) 저장되는 것이 페이징의 가장 중요한 특징. 이 덕분에 외부 단편화가 발생하지 않는다.
운영체제는 이처럼 흩어져 있는 페이지들의 위치를 페이지 테이블을 통해 정확히 기억하고 있다.
주소 변환 과정

1단계: 논리 주소 분할
CPU가 16비트 논리 주소 0000010111011110를 생성하면, MMU는 이것을 두 부분으로 나눈다.
- 페이지 번호 (p): 주소의 앞부분 6비트인 000001. 이 주소가 '어떤 페이지'에 속하는지를 나타낸다.
- 오프셋 (d): 주소의 뒷부분 10비트인 0111011110. 해당 페이지 내에서 '얼마나 떨어져 있는지'를 나타내는 상대적인 위치이다.
2단계: 페이지 테이블 조회
MMU는 1단계에서 얻은 페이지 번호(p=1)를 인덱스(index)로 사용하여, 이 프로세스 전용 페이지 테이블의 1번 항목을 조회한다.
- 페이지 테이블의 1번 항목에는 000110이라는 값이 저장되어 있다.
- 이 값은 해당 논리 페이지가 물리 메모리의 6번 프레임에 저장되어 있다는 의미. 이 값을 프레임 번호(f)라고 함.
3단계: 물리 주소 생성
이제 MMU는 2단계에서 찾은 프레임 번호(f)와 1단계의 오프셋(d)을 합쳐 최종 물리 주소를 만듦.
- 물리 주소 = 프레임 번호 (f) + 오프셋 (d)
- 000110 (프레임 번호) + 0111011110 (오프셋) = 0001100111011110
5-2. 세그먼테이션 (Segmentation)

프로그램을 논리적인 단위(Main, Stack, Function 등)인 세그먼트(Segment)로 나누어 관리한다. 크기가 가변적이다.
세그먼테이션은 이처럼 논리적인 코드와 데이터 단위를 그대로 하나의 세그먼트로 정의하여 관리한다.
운영체제는 각 세그먼트의 정보를 세그먼트 테이블(Segment Table)에 저장하여 관리한다.
- limit: 해당 세그먼트의 크기를 나타냄 (메모리 보호용)
- base: 해당 세그먼트가 물리 메모리에 저장된 시작 주소를 나타냄 (주소 변환용)
세그먼테이션에서의 논리 주소는 <세그먼트 번호, 오프셋>으로 구성된다. 예를 들어, 논리 주소 <2, 100> (2번 세그먼트의 시작으로부터 100만큼 떨어진 위치)은 다음과 같이 변환된다.
- 세그먼트 테이블에서 2번 항목을 찾는다 (base=4300, limit=400)
- 보호 검사: 오프셋(100)이 limit(400)보다 작은지 확인 (100 < 400 이므로 유효)
- 물리 주소 계산: 물리 주소 = base + 오프셋 = 4300 + 100 = 4400
특징
- 보호와 공유 용이: '코드'나 '데이터' 같은 의미 단위로 쪼개져 있어 권한 관리가 쉽다.
- 외부 단편화 발생: 가변 크기이므로 동적 분할처럼 틈새 공간이 생길 수 있다.
주소 변환

1단계: 논리 주소 분할
MMU는 CPU가 생성한 16비트 논리 주소를 <세그먼트 번호(s), 오프셋(d)>으로 나눈다.
- 세그먼트 번호 (s): 앞의 4비트 0001. '어떤 세그먼트'인지를 나타낸다.
- 오프셋 (d): 뒤의 12비트 011111110000. 해당 세그먼트 시작점으로부터 '얼마나 떨어져 있는지'를 나타낸다.
2단계: 세그먼트 테이블 조회
MMU는 세그먼트 번호(s=1)를 인덱스로 사용하여 세그먼트 테이블의 1번 항목을 조회. 해당 항목에는 두 가지 정보가 있다.
- 길이(limit): 세그먼트의 크기. 보호 검사에 사용됨 (오프셋이 길이보다 크면 메모리 접근 오류).
- 시작 주소(base): 세그먼트의 물리 메모리 시작 주소.
3단계: 물리 주소 계산
MMU는 테이블에서 읽어온 시작 주소(base)와 논리 주소의 오프셋(d)을 더하여 최종 물리 주소를 계산한다.
물리 주소 = 시작 주소 (base) + 오프셋 (d)
이처럼 세그먼테이션은 논리적 단위에 기반한 유연한 메모리 보호 및 공유를 가능하게 하지만, 외부 단편화라는 문제점을 안고 있다.
출처
- William Stallings, 운영체제 내부구조 및 설계원리
'Operating System' 카테고리의 다른 글
| [운영체제 OS] Scheduling (1) | 2026.02.01 |
|---|---|
| [운영체제 OS] Virtual Memory (0) | 2026.02.01 |
| [운영체제 OS] Deadlock (1) | 2026.02.01 |
| [운영체제 OS] Concurrency (0) | 2026.02.01 |
| [운영체제 OS] Thread (0) | 2026.02.01 |