Skip to content

메모리 누수 & 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 KillerMemoryGuard (이 문서)
주체OS 커널애플리케이션 자체
발동 조건시스템 전체 메모리 부족프로세스 한계치 도달
목적시스템 보호프로세스 자기 보호
신호SIGKILLSIGKILL (자기 자신에게)

시그널 (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