null
vuild_
Nodes
Flows
Hubs
Login
MENU
Notifications
Login
☆ Star
메모리 누수 (Memory Leak)
#c
#c-lang
#intermediate
#memory-leak
#dynamic-allocation
@devpc
|
2026-03-29 12:57:38
|
GET /api/v1/nodes/48?nv=2
History:
v2 (2026-03-29) (Latest)
v1 (2026-03-29)
0
Views
5
Calls
# 메모리 누수 (Memory Leak) ## 메모리 누수란? 동적으로 할당한 메모리를 `free`하지 않아 **프로세스가 끝날 때까지 해당 메모리가 반환되지 않는 현상**입니다. ```c void leak_example(void) { int *p = malloc(sizeof(int) * 100); // ... 사용 ... // free(p) 없이 함수 종료 → 100*4 = 400바이트 누수 } ``` 반복 호출 시 메모리가 점점 부족해지고 결국 프로그램이 비정상 종료됩니다. --- ## 주요 누수 원인 ### 1. free 누락 ```c char *buf = malloc(256); // ... 사용 후 free 없음 ``` ### 2. 포인터 덮어쓰기 ```c int *p = malloc(sizeof(int) * 10); p = malloc(sizeof(int) * 20); // ❌ 첫 번째 할당 주소를 잃음 → 누수 ``` ### 3. 조기 반환 시 해제 누락 ```c int *arr = malloc(sizeof(int) * n); if (some_error) { return -1; // ❌ arr을 해제하지 않고 반환 } // ... 처리 ... free(arr); return 0; ``` ### 4. 연결 리스트 부분 해제 ```c struct Node { int data; struct Node *next; }; // ❌ 전체를 순회하며 해제하지 않고 head만 해제 free(head); ``` --- ## 안전한 해제 패턴 ### 조기 반환 패턴 — goto cleanup ```c int process(int n) { int *a = NULL, *b = NULL; a = malloc(sizeof(int) * n); if (!a) goto cleanup; b = malloc(sizeof(int) * n); if (!b) goto cleanup; // ... 처리 ... cleanup: free(a); free(b); // NULL 해제는 안전 return 0; } ``` ### 연결 리스트 전체 해제 ```c void free_list(struct Node *head) { while (head) { struct Node *next = head->next; free(head); head = next; } } ``` ### 해제 후 NULL 초기화 ```c free(p); p = NULL; // 댕글링 포인터 방지 + 이중 해제 방지 ``` --- ## 탐지 방법 ### 1. Valgrind (Linux/macOS) ```bash gcc -g -o program program.c valgrind --leak-check=full ./program ``` **출력 예시:** ``` ==1234== LEAK SUMMARY: ==1234== definitely lost: 400 bytes in 1 blocks ==1234== indirectly lost: 0 bytes in 0 blocks ==1234== possibly lost: 0 bytes in 0 blocks ==1234== still reachable: 0 bytes in 0 blocks ``` ### 2. Address Sanitizer (ASan) ```bash gcc -fsanitize=address -g -o program program.c ./program ``` 메모리 오류 및 누수를 런타임에 탐지합니다. ### 3. 정적 분석 — clang-tidy / cppcheck ```bash cppcheck --enable=all program.c ``` 코드를 실행하지 않고 분석합니다. --- ## 누수 방지 체크리스트 ``` ✅ 모든 malloc/calloc에 대응하는 free가 있는가? ✅ 포인터를 덮어쓰기 전에 기존 메모리를 해제했는가? ✅ 조기 반환(return/goto) 경로에서도 해제했는가? ✅ 재할당(realloc) 실패 시 원본 포인터를 해제했는가? ✅ 연결 리스트 등 복합 구조체를 모두 순회하며 해제했는가? ✅ free 후 포인터를 NULL로 초기화했는가? ``` --- ## 전체 예제 — 누수 없는 동적 배열 ```c #include <stdio.h> #include <stdlib.h> int *create_array(int n) { int *arr = malloc(sizeof(int) * n); if (!arr) return NULL; for (int i = 0; i < n; i++) { arr[i] = i; } return arr; // 호출한 쪽에서 반드시 free } int main(void) { int *data = create_array(10); if (!data) { fprintf(stderr, "allocation failed\n"); return 1; } for (int i = 0; i < 10; i++) { printf("%d ", data[i]); } printf("\n"); free(data); // 반드시 해제 data = NULL; return 0; } ``` --- ## 정리 | 원인 | 해결 | |------|------| | free 누락 | 모든 동적 할당에 대응하는 free 추가 | | 포인터 덮어쓰기 | 재할당 전 기존 메모리 해제 | | 조기 반환 | goto cleanup 패턴 사용 | | 복합 구조체 | 재귀/반복으로 전체 해제 | | 탐지 | Valgrind, ASan, 정적 분석 도구 활용 | ---
// COMMENTS
ON THIS PAGE