메모리 누수 & OOM
메모리 누수가 어떻게 생기고, 어떤 패턴으로 쌓이다가, 결국 OOM과 SIGKILL로 프로세스가 종료되는지까지 순서대로 정리했습니다.
메모리 누수 (Memory Leak)
비유: 욕조에 물을 받는데 마개를 안 뽑는 것
정상적인 메모리 사용: 메모리 누수:
malloc() → 할당 🪣 malloc() → 할당 🪣
사용... 사용...
free() → 해제 🚿 free() 없음! ❌
[물 받고 → 빼고 → 반복] [물 받고 → 받고 → 받고 → 넘침!]코드로 보는 차이
c
// 정상: 할당 후 해제
void 정상함수() {
char* data = malloc(25MB); // 할당
// ... 사용 ...
free(data); // ← 반드시 해제!
}
// ❌ 누수: 해제 없음
void 누수함수() {
char* data = malloc(25MB); // 할당
// ... 사용 ...
// free(data); ← 이게 없음!
} // 함수 끝나도 메모리는 그대로 점유 중이 문서에서의 패턴
T+2초: malloc(25MB) free 없음 → 25MB 점유
T+5초: malloc(25MB) free 없음 → 50MB 점유
T+8초: malloc(25MB) free 없음 → 75MB 점유
T+11초: malloc(25MB) free 없음 → 100MB 점유 → 종료선형 증가 패턴 분석
이 문서에서 관찰된 패턴의 의미
메모리(MB)
100 | ● ← 종료
75 | ●
50 | ●
25 | ●
0 +----+----+----+----+
0 3 6 9 (초)
기울기 = 25MB / 3초 ≈ 8.3MB/초
→ 일정한 기울기 = 규칙적인 누수
→ 랜덤하지 않음 = 의도된 동작 or 반복 루프패턴으로 알 수 있는 것
- 랜덤 누수: 불규칙한 증가 → 버그성 누수
- 선형 누수 (이 경우): 규칙적 증가 → 반복 루프에서 해제 없이 할당
python
# 추정되는 내부 동작 (의사 코드)
def memory_worker():
while True:
data = allocate(25 * MB) # 할당
# free(data) ← 이게 없음!
time.sleep(3) # 3초 대기OOM (Out of Memory)
비유: 주차장이 꽉 찬 상황
주차장(메모리)이 꽉 찼는데 새 차(프로세스)가 들어오려 함 → 관리인(OS)이 강제로 차를 견인(프로세스 종료)
OOM 발생 흐름:
메모리 요청
│
▼
사용 가능한 메모리 있음? ──YES──→ 할당 성공 ✅
│
NO
│
▼
스왑(Swap) 공간 있음? ──YES──→ 스왑 사용 (느려짐 ⚠️)
│
NO
│
▼
OOM Killer 발동! 💀
│
▼
희생 프로세스 선택 → SIGKILL 전송 → 강제 종료Linux OOM Killer vs 이 문서의 MemoryGuard
| 구분 | Linux OOM Killer | MemoryGuard (이 문서) |
|---|---|---|
| 주체 | OS 커널 | 애플리케이션 자체 |
| 발동 조건 | 시스템 전체 메모리 부족 | 프로세스 한계치 도달 |
| 목적 | 시스템 보호 | 프로세스 자기 보호 |
| 신호 | SIGKILL | SIGKILL (자기 자신에게) |
시그널 (Signal) - SIGKILL
비유: 프로세스에게 보내는 메시지
Signal 종류:
┌──────────┬──────────────────────────────────────────┐
│ SIGTERM │ "정리하고 종료해줘" (부드러운 요청) │
│ SIGKILL │ "즉시 종료!" (거부 불가, OS가 강제 실행) │
│ SIGINT │ "Ctrl+C" (인터럽트) │
│ SIGSEGV │ "잘못된 메모리 접근!" (세그폴트) │
└──────────┴──────────────────────────────────────────┘
이 문서:
MemoryGuard → SIGKILL → 프로세스 ID 7 즉시 종료
↑
핸들러 등록 불가
= 프로세스가 막을 방법 없음전체 개념 연결 지도
멀티스레드 환경에서 시작해 누수 → 선형 증가 → MemoryGuard → SIGKILL → OOM으로 이어지는 전체 흐름입니다.
MULTI_THREAD_ENABLE=True
│
▼
멀티스레드 환경
│
├──→ 데드락 위험 ⚠️
│
└──→ 여러 스레드가 Heap 동시 접근
│
▼
메모리 누수 (Memory Leak)
[malloc은 있고 free는 없음]
│
▼
Heap 선형 증가
(3초마다 +25MB)
│
▼
MEMORY_LIMIT 도달
(100MB >= 100MB)
│
▼
MemoryGuard 발동
│
▼
SIGKILL → OOM정리
| 단계 | 내용 |
|---|---|
| 메모리 누수 | malloc() 은 있고 free() 는 없음 → 함수가 끝나도 메모리 점유 |
| 선형 증가 | 3초마다 +25MB (≈ 8.3MB/초), 규칙적 증가 = 반복 루프에서 해제 없이 할당 |
| OOM | 메모리·스왑 모두 부족하면 OOM Killer가 희생 프로세스에 SIGKILL |
| MemoryGuard | 애플리케이션이 한계치(100MB) 도달 시 자기 자신에게 SIGKILL |
| SIGKILL | 거부 불가, 핸들러 등록 불가 → 프로세스가 막을 방법 없음 |
출처: Codyssey-B1/B4-2
