메모리 단편화가 발생하는 이유와 내부·외부 단편화 관리

메모리 단편화의 내부·외부 단편화 차이, 고정·가변 분할 특성, 페이징과 압축을 통한 관리 방법을 정리합니다.

2026-08-14 · 최초 발행 2025-12-28

남은 메모리와 실제 할당 가능 공간은 다르다

메모리가 충분히 남아 있어도 새 프로세스를 적재하지 못할 수 있다. 자유 공간이 작은 조각으로 흩어져 큰 연속 블록을 만들지 못하는 경우다. 반대로 프로세스에 메모리를 할당했더라도, 그 영역 안에는 실제 사용하지 않는 공간이 남을 수 있다.

이처럼 주기억장치에서 프로그램 실행에 쓰이지 못하고 낭비되는 공간을 단편화(Fragmentation)라고 한다. RAM의 메모리 할당 영역에서 발생하며, 메모리 활용도와 시스템 성능을 떨어뜨린다. 낭비가 할당 영역 안에 있느냐, 자유 영역 사이에 있느냐에 따라 내부 단편화와 외부 단편화로 나뉜다.

메모리 단편화내부 단편화(Internal Fragmentation)외부 단편화(External Fragmentation)할당된 영역 내부의사용되지 않는 공간할당되지 않은 영역이작게 분할되어 사용 불가고정 크기 할당의 문제가변 크기 할당의 문제

단편화는 두 가지 모습으로 메모리 낭비를 만든다. 자유 메모리의 총량은 충분하지만 연속적인 큰 블록이 없어 적재에 실패할 수 있고, 이미 할당한 공간 가운데 일부만 사용되어 나머지가 그대로 남을 수도 있다.

할당된 블록 안에서 남는 내부 단편화

내부 단편화(Internal Fragmentation)는 프로세스에 배정된 메모리 영역 내부에서 발생하는 낭비다. 할당 단위가 실제 요구량보다 크면 차이가 남는다.

내부 단편화 크기 = 할당된 크기(n) - 실제 필요한 크기(m)
조건: n ≥ m
프로세스요구: m bytes할당 단위:n bytes (n≥m)프로세스 할당사용: m bytes낭비: (n-m) bytes내부 단편화

고정 크기 블록을 사용하는 상황에서는 요구량이 블록 크기에 정확히 맞지 않으면 남는 영역이 생긴다.

블록 크기: 1024 bytes (1KB)
프로세스 요구: 900 bytes
할당: 1024 bytes
사용: 900 bytes
내부 단편화: 124 bytes (약 12%)

페이지 단위 할당에서도 마지막 페이지는 완전히 채워지지 않을 수 있다.

페이지 크기: 4096 bytes (4KB)
프로세스 크기: 10,000 bytes
필요 페이지: 3개 (12KB)
실제 사용: 10,000 bytes
내부 단편화: 2,096 bytes (약 21%)
할당된 블록1024 bytes사용 영역900 bytes내부 단편화124 bytes

고정 분할에서는 메모리를 미리 정해진 크기로 나누고 각 파티션에 하나의 프로세스를 배정한다. 프로세스 크기와 파티션 크기가 다르면 내부 단편화가 발생한다. 페이징 시스템도 고정 크기 페이지를 사용하므로 마지막 페이지에서 내부 단편화가 주로 나타나며, 페이지 크기가 클수록 단편화가 커진다.

흩어진 자유 공간이 만드는 외부 단편화

외부 단편화(External Fragmentation)는 할당되지 않은 자유 메모리가 작은 조각으로 나뉜 상태다. 자유 공간의 합은 충분해도 필요한 크기의 연속 영역이 없으면 프로세스를 적재할 수 없다.

∑(자유 공간 조각들) ≥ 프로세스 크기
그러나 max(자유 공간 조각) < 프로세스 크기
초기 상태:연속된 자유 공간프로세스들할당 해제메모리 중간중간에 공간 생성작은 공간들이흩어져 있음 프로세스적재 불가

다음 상태에서는 총 자유 공간이 250MB지만, 새 프로세스가 요구하는 200MB를 담을 연속 공간은 없다.

총 메모리: 1000 MB
할당 상태:
  [프로세스A: 200MB] [자유: 50MB] [프로세스B: 300MB]
  [자유: 100MB] [프로세스C: 250MB] [자유: 100MB]

총 자유 공간: 250MB
새 프로세스 요구: 200MB
연속 공간 최대: 100MB
결과: 할당 실패 (외부 단편화)
할당 불가할당 불가Process A200MBFree50MBProcess B300MBFree100MBProcess C250MBFree100MBNew Process200MB

가변 분할은 프로세스 크기에 맞춰 동적으로 공간을 할당한다. 프로세스가 종료될 때 빈 공간이 생기고, 시간이 지날수록 이 공간들이 흩어져 외부 단편화가 심해진다. malloc/free를 반복하는 힙(heap) 영역이나 장시간 실행되는 프로그램에서 주로 확인할 수 있다.

분할 방식이 바꾸는 단편화 양상

고정 분할은 메모리를 고정 크기 파티션으로 미리 나누는 방식이다. 각 파티션에는 하나의 프로세스를 배정하므로 구현과 할당이 단순하고 빠르다.

고정 분할파티션 1100KB파티션 2200KB파티션 3300KB파티션 4400KB내부 단편화내부 단편화외부 단편화외부 단편화

프로세스가 파티션보다 작으면 내부 단편화가 생긴다. 프로세스가 어떤 파티션에도 맞지 않는 경우에는 외부 단편화가 발생한다.

파티션 크기: [100KB, 200KB, 300KB]
프로세스 크기: 150KB

- 100KB 파티션: 작아서 할당 불가 (외부 단편화)
- 200KB 파티션: 할당 가능, 50KB 낭비 (내부 단편화)
- 300KB 파티션: 할당 가능, 150KB 낭비 (내부 단편화)

가변 분할은 프로세스 요구 크기에 맞춰 공간을 동적으로 배정한다. 공간 활용에는 유리하지만 할당 알고리즘이 더 복잡하며, 시간이 지나면 외부 단편화가 생긴다.

초기프로세스 적재일부 종료 프로세스 적재외부 단편화 발생||||||||||||||||||||전체 자유[A][B][C]||||||연속 할당[A]||[C]|||||| 공간 생성[A]|[D][C][E]|||조각난 공간외부 단편화
프로세스 A: 150KB 할당 → 정확히 150KB 사용
프로세스 B: 200KB 할당 → 정확히 200KB 사용
프로세스 A 종료 → 150KB 빈 공간 생성
새 프로세스 C: 200KB 요구 → 150KB 공간에 할당 불가
특성 고정 분할 가변 분할
파티션 크기 고정 가변
할당 방식 정적 동적
내부 단편화 발생 미발생
외부 단편화 발생 발생
구현 복잡도 낮음 높음
할당 속도 빠름 느림
메모리 효율 낮음 높음
사용 사례 초기 시스템 현대 시스템

자유 공간을 합치거나 재배치하는 방법

인접한 자유 공간은 통합(Coalescing)으로 하나의 블록으로 합칠 수 있다. 외부 단편화를 일부 완화하며, 구현이 간단하고 오버헤드가 낮아 실시간으로 적용할 수 있다. 다만 인접하지 않은 조각까지 합칠 수는 없으므로 완전한 해결책은 아니다.

통합[Process A][Free 50MB][Free 100MB][Process B]인접한 자유 공간통합[Process A][Free 150MB][Process B]
def coalesce_free_blocks(memory):
    merged = []
    current = memory[0]

    for block in memory[1:]:
        if current.is_free and block.is_free and current.is_adjacent(block):
            # 인접한 자유 블록 통합
            current.size += block.size
        else:
            merged.append(current)
            current = block

    merged.append(current)
    return merged

압축(Compaction)은 프로세스를 메모리 한쪽으로 옮겨 자유 공간을 하나의 연속 블록으로 만드는 방식이다. 외부 단편화를 완전히 제거하고 큰 연속 공간을 확보할 수 있지만, 모든 프로세스를 이동해야 한다. 압축 중 시스템이 정지하고 CPU 시간을 소비하며 주소 재배치도 필요하다.

압축[P1][Free][P2][Free][P3][Free]압축[P1][P2][P3][Free(통합)]프로세스들을한쪽으로 이동

압축은 일정 시간마다 실행하거나, 단편화 정도가 특정 수준을 넘었을 때, 대형 프로세스 할당이 실패했을 때, 또는 시스템 부하가 낮은 유휴 시간에 실행할 수 있다.

O(n × m)
n: 프로세스 수
m: 평균 프로세스 크기

연속 할당을 피하는 페이징과 세그먼테이션

페이징(Paging)은 프로세스를 고정 크기 페이지로, 물리 메모리를 같은 크기의 프레임으로 나누는 방식이다. 페이지는 연속된 물리 공간에 놓일 필요가 없으며 페이지 테이블이 페이지와 프레임의 대응을 관리한다.

매핑매핑매핑프로세스페이지 04KB페이지 14KB페이지 24KB물리 메모리프레임 54KB프레임 24KB프레임 94KB페이지 테이블

페이징은 연속 공간을 요구하지 않으므로 외부 단편화를 해결하고, 빈 프레임을 모두 활용할 수 있다. 그러나 마지막 페이지에는 내부 단편화가 남고 페이지 테이블 관리와 주소 변환 비용이 발생한다. TLB 미스 시 성능 저하도 고려해야 한다.

평균 내부 단편화 = 페이지 크기 / 2
페이지 크기가 클수록 단편화 증가
페이지 크기 장점 단점
작음 (1KB) 내부 단편화 감소 페이지 테이블 크기 증가
중간 (4KB) 균형잡힌 성능 일반적 선택
큼 (2MB) 페이지 테이블 작음 내부 단편화 증가

세그먼테이션(Segmentation)은 코드, 데이터, 스택, 힙처럼 의미 있는 논리 단위로 메모리를 나누고, 각 세그먼트에는 가변 크기를 부여한다. 논리 구조를 반영하고 보호와 공유에 유리하며 내부 단편화는 없다. 대신 외부 단편화와 세그먼트 테이블 관리 비용이 따른다.

프로세스CodeSegmentDataSegmentStackSegmentHeapSegment메모리Code 영역Data 영역Stack 영역Heap 영역

두 기법을 결합하면 세그먼트의 논리 구조를 유지하면서, 각 세그먼트를 다시 페이지로 나눠 프레임에 매핑할 수 있다.

프로세스세그먼트로 분할 세그먼트를페이지로 분할페이지를 프레임에매핑장점논리적 구조 + 효율적 할당내부/외부 단편화 최소화

이 방식은 외부 단편화를 제거하고 유연한 메모리 관리를 제공하지만, 구현이 복잡해지고 이중 주소 변환 및 메모리 테이블 비용이 늘어난다.

운영체제와 프로그램에서의 관리

Linux에서는 Buddy System으로 2의 거듭제곱 크기 블록을 관리하고, Slab Allocator는 객체 크기별 캐시를 사용한다. 페이징은 4KB 기본 페이지를 사용하며 Huge Pages는 2MB/1GB 대형 페이지를 제공한다.

Windows는 Virtual Memory Manager를 사용하며, 페이징은 4KB 페이지, Large Pages는 2MB 페이지를 사용한다. 동적 메모리 압축도 적용한다.

임베디드 시스템에서는 예측 가능한 성능을 위해 고정 분할을 사용하고 동적 할당을 제한하며 압축을 최소화한다.

반복적으로 생성·삭제되는 객체에는 메모리 풀을 적용할 수 있다.

// 고정 크기 객체 풀
struct MemoryPool {
    void* blocks;
    size_t block_size;
    size_t num_blocks;
    void* free_list;
};

void* pool_alloc(MemoryPool* pool) {
    if (pool->free_list == NULL) return NULL;
    void* block = pool->free_list;
    pool->free_list = *(void**)block;
    return block;
}

메모리 풀은 단편화를 막고 할당과 해제를 빠르게 하며 예측 가능한 성능을 제공한다. 객체 재사용은 자주 생성·삭제되는 객체의 풀링을 통해 단편화를 줄이고, 정렬을 고려한 할당은 캐시 효율을 높이며 단편화를 최소화한다.

단편화 상태를 읽는 지표와 도구

외부 단편화는 최대 자유 블록과 전체 자유 공간의 관계로 살필 수 있다.

외부 단편화 비율 = (최대 자유 블록 크기) / (총 자유 공간 크기)
0에 가까울수록 심각 (작은 조각 다수)
1에 가까울수록 양호 (큰 연속 공간)

내부 단편화와 전체 활용률은 다음 식으로 확인한다.

내부 단편화 비율 = (총 낭비 공간) / (총 할당 공간)
활용률 = (사용 중인 메모리) / (총 메모리)

Linux에서는 버디 시스템, 슬랩 할당자, 프로세스 메모리 맵을 다음 명령으로 확인할 수 있다.

# 메모리 단편화 확인
cat /proc/buddyinfo

# 슬랩 할당자 상태
cat /proc/slabinfo

# 메모리 맵
cat /proc/<pid>/maps

Windows에서는 성능 모니터와 메모리 진단 명령을 사용할 수 있다.

# 성능 모니터
perfmon /res

# 메모리 진단
mdsched

고정 분할에서는 내부와 외부 단편화가 모두 생길 수 있고, 가변 분할에서는 외부 단편화가 문제가 된다. 통합은 인접한 자유 공간을 묶고, 압축은 프로세스를 이동해 외부 단편화를 완전히 제거한다. 현대 운영체제는 주로 페이징으로 외부 단편화를 해결하며, 페이지 크기 선택으로 내부 단편화를 관리한다. 메모리 풀, 버디 시스템, 슬랩 할당자는 이러한 관리 방식을 보완한다.

메모리 관리단편화운영체제페이징세그먼테이션