"malloc은 공짜가 아닙니다. 장부(Bookkeeping)를 관리하는 거대한 도서관 사서입니다."
많은 분들이 malloc(size)을 호출하면 마법처럼 메모리가 뚝 떨어진다고 생각합니다. 하지만 실제로는 C 런타임 라이브러리(Glibc, Heap Manager)가 운영체제로부터 큰 땅(Heap)을 미리 빌려놓고, 사용자가 요청할 때마다 칼로 잘라서 내어주는 것입니다.
이때, "누구에게 얼마만큼 빌려줬는지" 기록해야 하기 때문에, 실제로는 요청한 크기보다 더 많은 메모리를 사용합니다.
malloc(16)을 호출했을 때 메모리에 16바이트만 생기는 것이 아닙니다. 투시해 봅시다.
힙 관리자는 메모리를 청크(Chunk) 단위로 관리합니다.
[ Heap Memory Block ]
Address | Content (What's inside)
------------+------------------------------------------
0x1000 | [ Size: 24 ] [ Flag: Used ] <-- Metadata (Header)
------------+------------------------------------------
0x1004 | [ User Data (16 Bytes) ] <-- ptr (반환되는 주소)
| ...
0x1013 | ...
------------+------------------------------------------
0x1014 | [ Padding (Alignment) ] <-- 4의 배수 맞춤
------------+------------------------------------------
0x1018 | [ Size: ... ] [ Flag: ... ] <-- 다음 블록의 헤더
ptr)의 바로 앞부분(4~8바이트)에는 이 블록의 크기와 사용 여부가 기록되어 있습니다.free(ptr) 함수가 크기 인자를 받지 않아도 되는 이유입니다. free는 내부적으로 ptr - Header_Size 위치를 읽어서 "아, 이 블록은 24바이트짜리구나"라고 알아냅니다.메모리를 계속 할당하고 해제하다 보면, 힙 메모리는 구멍 뚫린 치즈처럼 변합니다.
free)malloc(30)Q: 왜 힙 관리가 스택보다 느리고 복잡한가요?
A: "스택은 접시 쌓기이고, 힙은 테트리스이기 때문입니다."
메모리 관리의 내부를 알았을 때 피해야 할 코드 패턴입니다.
작은 크기의 메모리를 수천 번 malloc/free 하는 것은 최악입니다.
/* BAD Practice: 힙 단편화 유발 */
for (int i = 0; i < 1000; i++) {
char *p = malloc(16); // 16바이트 짜리 구멍을 수없이 만듦
// ... 작업 ...
free(p);
}
free 후 댕글링 포인터(Dangling Pointer)char *ptr = malloc(10);
free(ptr);
// ptr은 여전히 0x1004를 가리키고 있음! (집은 팔았는데 열쇠를 안 버림)
*ptr = 'A'; // Use-After-Free 버그!
// 만약 0x1004가 다른 용도로 재할당되었다면? 치명적인 데이터 오염 발생
free 직후에 반드시 포인터를 NULL로 미십시오.free(ptr);
ptr = NULL; // 안전장치"프로그램 끄면 OS가 알아서 수거해가니까 괜찮지 않나요?"
핵심정리:
"malloc을 한다는 건, 시스템에게 '비용이 많이 드는 부탁'을 하는 것과 같습니다. 내부적으로 메타데이터를 쓰고, 빈 공간을 탐색하는 무거운 작업이죠.
이 원리를 이해하셨다면, 왜 자원이 제한적인 임베디드 시스템이나 실시간 시스템(RTOS)에서malloc을 악마 취급하는지 직감하실 겁니다."