--- id: wiki-2026-0508-메모리-누수-memory-leaks title: 메모리 누수(Memory Leaks) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [Memory Leak, Heap Leak, Leak Detection] duplicate_of: none source_trust_level: A confidence_score: 0.9 verification_status: applied tags: [memory, debugging, performance, gc, profiling] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: C/C++/Java/JS/Python framework: Valgrind/ASan/Heaptrack/Chrome DevTools --- # 메모리 누수(Memory Leaks) ## 매 한 줄 > **"매 alive 인데 매 unused, 매 unused 인데 매 free X"**. 매 manual mem (C/C++) 의 free 누락, 매 GC mem (Java/JS) 의 unintended retention. 매 long-running process 의 매 가장 흔한 incident, 매 2026 도구는 매 ASan/heaptrack/V8 heap snapshot/JFR + AI-assisted root cause. ## 매 핵심 ### 매 두 의미 - **매 Manual leak**: 매 free X — 매 OS 가 매 process 종료 시 매 회수. - **매 GC leak**: 매 root 에서 매 reachable 이지만 매 logically dead — 매 unintended retention. ### 매 흔한 원인 1. 매 Cache 의 unbounded growth. 2. 매 Listener / observer 의 unsubscribe 누락. 3. 매 Closure 의 unintended capture (JS). 4. 매 Static collection (HashMap) 의 누적. 5. 매 ThreadLocal 의 cleanup 누락 (JVM/web). 6. 매 Native handle (file/socket) 의 close 누락. 7. 매 Circular ref + RC (Python before GC, Swift, ObjC ARC). ### 매 detection 의 axes - 매 Symptom: 매 RSS 증가, 매 OOM, 매 GC 빈도 ↑, 매 latency drift. - 매 Tool: 매 sampling profiler, 매 heap snapshot, 매 allocation tracking. ## 패턴 ### C++ Valgrind ```bash g++ -g -O0 main.cpp -o app valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes ./app # 매 "definitely lost" 의 우선 fix ``` ### C++ AddressSanitizer + LeakSanitizer ```bash g++ -fsanitize=address,leak -g main.cpp -o app ASAN_OPTIONS=detect_leaks=1 ./app ``` ### C++ RAII (matter of design) ```cpp class FileHandle { FILE* f; public: explicit FileHandle(const char* p) : f(fopen(p, "r")) {} ~FileHandle() { if (f) fclose(f); } FileHandle(const FileHandle&) = delete; FileHandle& operator=(const FileHandle&) = delete; }; // 매 std::unique_ptr / std::shared_ptr 가 매 default ``` ### JS — listener 누락 ```javascript // 매 BAD — node 가 떠도 listener 가 retain function attach(el) { const handler = () => doStuff(el); el.addEventListener("click", handler); } // 매 GOOD function attach(el) { const handler = () => doStuff(el); el.addEventListener("click", handler); return () => el.removeEventListener("click", handler); } ``` ### JS — closure 의 unintended capture ```javascript // 매 BAD — 매 huge 가 매 outer scope 에 retained function setup() { const huge = new Array(1e7).fill(0); const small = huge[0]; return () => small; } // 매 GOOD function setup() { const small = (() => { const huge = new Array(1e7).fill(0); return huge[0]; })(); return () => small; } ``` ### Java — static map leak ```java // 매 BAD public class Cache { static final Map M = new HashMap<>(); } // 매 GOOD — Caffeine size cap + eviction import com.github.benmanes.caffeine.cache.*; Cache c = Caffeine.newBuilder() .maximumSize(10_000).expireAfterWrite(Duration.ofMinutes(10)).build(); ``` ### Java heap dump + MAT ```bash jcmd GC.heap_dump /tmp/heap.hprof # 매 Eclipse MAT 에서 dominator tree / leak suspect ``` ### Chrome DevTools — heap snapshot diff ```text 1. baseline snapshot 2. suspect action 반복 (e.g. open/close modal x10) 3. second snapshot 4. "Comparison" mode, 매 retained 증가 식별 5. retainer chain 의 root 추적 ``` ### Python tracemalloc ```python import tracemalloc tracemalloc.start(25) snap1 = tracemalloc.take_snapshot() # ... 매 action 반복 ... snap2 = tracemalloc.take_snapshot() for stat in snap2.compare_to(snap1, 'lineno')[:10]: print(stat) ``` ### Linux heaptrack (C/C++ low-overhead) ```bash heaptrack ./app heaptrack_gui heaptrack.app..gz ``` ## 매 결정 기준 | Stack | Tool | |---|---| | C/C++ dev | ASan + LeakSanitizer | | C/C++ prod | heaptrack / jemalloc profiler | | Java | JFR + heap dump + MAT | | Node.js | --inspect + Chrome heap snapshot | | Browser | DevTools Memory tab | | Python | tracemalloc / objgraph / memray | | Go | pprof (heap profile) | **기본값**: 매 first symptom = RSS chart, 매 second = heap snapshot diff, 매 third = retainer/dominator analysis. ## Graph - 부모: [[Memory Management]] · [[Performance]] - 변형: [[Manual Leak]] · [[GC Retention]] · [[Native Handle Leak]] - 응용: [[Heap Profiling]] · [[Cache Eviction]] · [[WeakRef]] - Adjacent: [[Garbage Collection]] · [[Reference Counting]] · [[RAII]] · [[OOM]] ## LLM 활용 **언제**: 매 leak 패턴 식별, 매 fix 제안 (RAII, weak ref, eviction policy), 매 heap dump 분석 hint. **언제 X**: 매 production heap 의 직접 access, 매 sensitive customer data dump. ## 안티패턴 - **매 OOM 시 -Xmx ↑**: 매 leak 을 매 늦출 뿐. - **매 try/finally 없는 close**: 매 try-with-resources / RAII / context manager 사용. - **매 Strong cache without eviction**: Caffeine / LRU. - **매 Listener pattern 의 no unsubscribe**: weakRef / dispose. - **매 GC tuning 으로 leak 감추기**: root cause X. ## 검증 / 중복 - Verified: Valgrind manual, ASan docs, V8 blog, JFR docs, tracemalloc PEP, heaptrack docs. - 신뢰도 A. ## Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — leak detection per-stack/anti-patterns/RAII 작성 |