메모리 할당 및 해제 동작과 메모리 단편화 예시

1. new/delete 방식에서의 메모리 할당 및 해제

new/delete를 사용하면, 힙 영역에서 필요한 크기의 메모리를 할당받습니다. 할당과 해제가 반복되면, 메모리 영역이 연속적으로 사용되지 않고 중간중간 빈 공간이 생겨 메모리 단편화(fragmentation)가 발생할 수 있습니다.

예시 다이어그램 (new/delete 방식):

[ 초기 메모리 힙 ]
+---------------------------------------------------+
|  [          Free Memory (연속된 공간)          ]  |
+---------------------------------------------------+

1) 객체 A (크기: 128 바이트) 할당:
+---------------------------------------------------+
| [A: 128] |          남은 Free Memory              |
+---------------------------------------------------+

2) 객체 B (크기: 256 바이트) 할당:
+---------------------------------------------------+
| [A: 128] | [B: 256] |         남은 Free Memory     |
+---------------------------------------------------+

3) 객체 A 삭제 (delete A):
+---------------------------------------------------+
| [ A: FREE ] | [B: 256] |         남은 Free Memory  |
+---------------------------------------------------+
        ↑
  이 영역은 비어 있으나,
  후속 할당 시 128 바이트가 필요하면 사용 가능하지만,
  다른 크기의 요청에서는 적절히 활용되지 못할 수 있음.

4) 객체 C (크기: 200 바이트) 할당 시:
+---------------------------------------------------+
| [ A: FREE ] | [B: 256] | [C: 200] |  남은 공간   |
+---------------------------------------------------+
  → 200바이트 할당이 A의 빈 공간과 인접하지 않으면
    두 영역을 결합하지 못해 내부 단편화가 발생.
  • 설명:
    • 객체 A가 삭제되면 128바이트의 빈 공간이 생깁니다.
    • 후에 200바이트와 같이 A보다 큰 객체를 할당할 경우, 이 빈 공간은 재사용되지 못하고 새로운 할당이 이루어집니다.
    • 이런 식으로 여러 객체의 할당/해제가 반복되면, 사용 가능한 전체 메모리 크기는 충분하지만 할당 가능한 연속된 블록이 부족해지는 현상이 발생합니다.

2. 메모리 풀 방식에서의 할당 및 해제

메모리 풀은 미리 일정 크기의 메모리 블록을 할당해두고, 필요 시 해당 블록을 재사용합니다. 이 방식은 할당/해제 시 포인터 조작만으로 빠르게 처리되며, 각 블록이 고정 크기이므로 단편화 문제가 크게 발생하지 않습니다.

예시 다이어그램 (메모리 풀 방식):

[ 메모리 풀 (Fixed Size Block Pool) ]
+--------+  +--------+  +--------+  +--------+  +--------+
| Block1 |  | Block2 |  | Block3 |  | Block4 |  | Block5 |
+--------+  +--------+  +--------+  +--------+  +--------+

1) 객체 A 할당 → Block2 사용:
+--------+  +--------+  +--------+  +--------+  +--------+
| Block1 |  |  [A]   |  | Block3 |  | Block4 |  | Block5 |
+--------+  +--------+  +--------+  +--------+  +--------+

2) 객체 A 삭제 → Block2 반환:
+--------+  +--------+  +--------+  +--------+  +--------+
| Block1 |  |  FREE  |  | Block3 |  | Block4 |  | Block5 |
+--------+  +--------+  +--------+  +--------+  +--------+

3) 객체 B 할당 → FREE 블록(Block2) 재사용:
+--------+  +--------+  +--------+  +--------+  +--------+
| Block1 |  |  [B]   |  | Block3 |  | Block4 |  | Block5 |
+--------+  +--------+  +--------+  +--------+  +--------+
  • 설명:
    • 메모리 풀은 미리 정해진 크기의 블록을 갖고 있으며, 객체 생성 시 사용 가능한 블록을 바로 할당합니다.
    • 객체 삭제 후 해당 블록은 다시 풀에 반환되므로, 다음 할당 요청 시 재사용됩니다.
    • 고정 크기 블록을 사용하므로, 메모리 단편화 문제가 거의 발생하지 않으며, 할당/해제 시간이 매우 일정합니다.

요약

  • new/delete 방식은 유연하지만, 많은 할당/해제 작업이 반복되면 메모리 단편화와 예측 불가능한 할당 시간이 발생할 수 있습니다.
  • 메모리 풀 방식은 미리 할당된 고정 크기 블록을 재사용하여 할당/해제 시간이 일정하고 빠르며, 메모리 단편화를 효과적으로 줄여줍니다.

다음 글에서는 메모리 풀 구현과 성능 테스트를 해보려고 합니다.