f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
173 lines
6.0 KiB
Markdown
173 lines
6.0 KiB
Markdown
---
|
|
id: wiki-2026-0508-gc-root
|
|
title: GC Root
|
|
category: 10_Wiki/Topics
|
|
status: verified
|
|
canonical_id: self
|
|
aliases: [Garbage Collection Root, GC 루트, Root Set]
|
|
duplicate_of: none
|
|
source_trust_level: A
|
|
confidence_score: 0.9
|
|
verification_status: applied
|
|
tags: [gc, jvm, memory, runtime]
|
|
raw_sources: []
|
|
last_reinforced: 2026-05-10
|
|
github_commit: pending
|
|
tech_stack:
|
|
language: Java/Kotlin
|
|
framework: JVM/HotSpot/ZGC
|
|
---
|
|
|
|
# GC Root
|
|
|
|
## 매 한 줄
|
|
> **"매 도달 가능성(reachability) 의 출발점"**. GC Root 는 garbage collector 가 live object 를 판별하기 위해 traversal 을 시작하는 reference set. 매 root 에서 도달 불가능한 object 는 collectible 로 marking 된다. JVM, .NET CLR, V8, Go runtime 모두 같은 개념을 공유한다.
|
|
|
|
## 매 핵심
|
|
|
|
### 매 GC Root 종류 (HotSpot 기준)
|
|
- **Stack reference**: 매 thread 의 local variable / parameter / operand stack.
|
|
- **Static field**: 매 loaded class 의 static reference.
|
|
- **JNI local/global**: 매 native code 가 hold 한 reference.
|
|
- **Active thread**: 매 살아있는 `Thread` object 자체.
|
|
- **Class metadata**: 매 ClassLoader, Class object (Metaspace).
|
|
- **Synchronization monitor**: 매 `synchronized` 로 lock 된 object.
|
|
- **Weak/Soft/Phantom 제외**: 매 reachability 약한 reference 는 root 가 아님.
|
|
|
|
### 매 Reachability tier
|
|
1. **Strongly reachable**: root 에서 strong ref 만으로 도달 → never collected.
|
|
2. **Softly reachable**: SoftReference 로만 도달 → 매 memory pressure 시 collect.
|
|
3. **Weakly reachable**: WeakReference 만 → 매 next GC cycle 에 collect.
|
|
4. **Phantom reachable**: PhantomReference → enqueue 후 cleaning.
|
|
5. **Unreachable**: → collectible.
|
|
|
|
### 매 응용
|
|
1. **Memory leak 진단** (heap dump → root path 추적).
|
|
2. **Escape analysis** (root 도달 안 되는 local → stack alloc).
|
|
3. **Concurrent GC 의 root scanning** (ZGC, Shenandoah, G1 의 phase 1).
|
|
|
|
## 💻 패턴
|
|
|
|
### 1. Heap dump 에서 root path 찾기 (Eclipse MAT / jhat)
|
|
```bash
|
|
# JVM heap dump 생성
|
|
jcmd <pid> GC.heap_dump /tmp/heap.hprof
|
|
|
|
# Eclipse MAT CLI 로 leak suspects 분석
|
|
./MemoryAnalyzer -consoleLog -application org.eclipse.mat.api.parse \
|
|
/tmp/heap.hprof org.eclipse.mat.api:suspects
|
|
```
|
|
|
|
### 2. JFR 로 GC root 통계 수집 (JDK 21+)
|
|
```bash
|
|
java -XX:StartFlightRecording=duration=60s,filename=app.jfr,settings=profile \
|
|
-XX:+UseZGC -Xmx4g -jar app.jar
|
|
|
|
jfr print --events GarbageCollection,GCReferenceStatistics app.jfr
|
|
```
|
|
|
|
### 3. WeakReference 로 root 진입 회피
|
|
```java
|
|
import java.lang.ref.WeakReference;
|
|
import java.util.WeakHashMap;
|
|
|
|
// Cache 가 GC root 가 되어 leak 발생하는 anti-pattern 회피
|
|
public class Cache<K, V> {
|
|
private final WeakHashMap<K, V> map = new WeakHashMap<>();
|
|
|
|
public void put(K key, V value) { map.put(key, value); }
|
|
public V get(K key) { return map.get(key); }
|
|
// key 가 외부에서 strong ref 사라지면 entry 자동 제거
|
|
}
|
|
```
|
|
|
|
### 4. ThreadLocal leak 회피 (매 typical root leak)
|
|
```java
|
|
public class RequestContext {
|
|
private static final ThreadLocal<UserSession> CTX = new ThreadLocal<>();
|
|
|
|
public static void set(UserSession s) { CTX.set(s); }
|
|
public static UserSession get() { return CTX.get(); }
|
|
|
|
// 매 critical: thread pool 환경에서 반드시 remove() 호출
|
|
public static void clear() { CTX.remove(); }
|
|
}
|
|
|
|
// Servlet filter 에서:
|
|
try {
|
|
RequestContext.set(session);
|
|
chain.doFilter(req, res);
|
|
} finally {
|
|
RequestContext.clear(); // 매 root reference 끊기
|
|
}
|
|
```
|
|
|
|
### 5. JNI global ref 정리 (native code 가 GC root)
|
|
```c
|
|
// JNI: global ref 는 명시적으로 free 해야 함
|
|
jobject globalRef = (*env)->NewGlobalRef(env, localObj);
|
|
// ... 사용 ...
|
|
(*env)->DeleteGlobalRef(env, globalRef); // 매 빠뜨리면 영구 leak
|
|
```
|
|
|
|
### 6. Static field 로 의도된 long-lived root
|
|
```kotlin
|
|
object AppMetrics { // 매 Kotlin object → static singleton → GC root
|
|
private val counter = AtomicLong(0)
|
|
fun increment() = counter.incrementAndGet()
|
|
fun snapshot() = counter.get()
|
|
}
|
|
```
|
|
|
|
### 7. ZGC / Shenandoah concurrent root scanning 활성화
|
|
```bash
|
|
# JDK 21+: ZGC generational
|
|
java -XX:+UseZGC -XX:+ZGenerational \
|
|
-XX:SoftMaxHeapSize=8g -Xmx16g -jar app.jar
|
|
|
|
# Shenandoah
|
|
java -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -jar app.jar
|
|
```
|
|
|
|
### 8. Async profiler 로 allocation root 찾기
|
|
```bash
|
|
./profiler.sh -e alloc -d 60 -f alloc.html <pid>
|
|
# 매 flamegraph 에서 root → leaking site path 시각화
|
|
```
|
|
|
|
## 매 결정 기준
|
|
| 상황 | Approach |
|
|
|---|---|
|
|
| Long-lived cache | `WeakHashMap` / Caffeine `weakKeys()` |
|
|
| Per-request state in pool | `ThreadLocal` + `try/finally remove()` |
|
|
| Native handle wrapping | `Cleaner` (java.lang.ref.Cleaner, JDK 9+) |
|
|
| Listener registration | `WeakReference` 로 listener wrap |
|
|
| 매 short-lived burst alloc | 매 그냥 strong ref + young gen 의존 |
|
|
|
|
**기본값**: 매 strong ref + escape analysis 신뢰. WeakReference 는 매 진짜 leak 패턴 (cache, listener, ThreadLocal in pool) 에만.
|
|
|
|
## 🔗 Graph
|
|
- 부모: [[Garbage Collection]]
|
|
- 응용: [[Memory Leak Detection]]
|
|
|
|
## 🤖 LLM 활용
|
|
**언제**: heap dump 의 leak suspect 해석, root path 의 의미 설명, ThreadLocal/static leak pattern detection.
|
|
**언제 X**: 매 production 의 실제 GC tuning (real profiling 데이터 없이 추측 X).
|
|
|
|
## ❌ 안티패턴
|
|
- **Static collection 무한 grow**: `static List` 에 매 add 만 하고 remove 안 함 → 영구 root.
|
|
- **ThreadLocal in pool no remove**: 매 thread 재사용 시 이전 request data 가 root 로 남음.
|
|
- **JNI GlobalRef leak**: native 에서 `DeleteGlobalRef` 누락.
|
|
- **Anonymous inner class capture**: `new Runnable() {}` 가 outer `this` 를 capture → outer 가 root 에 매달림.
|
|
- **Listener 등록 후 unregister 안 함**: 매 EventBus, Observer 패턴의 classic leak.
|
|
|
|
## 🧪 검증 / 중복
|
|
- Verified (OpenJDK HotSpot source, JEP 376/439, Eclipse MAT docs).
|
|
- 신뢰도 A.
|
|
|
|
## 🕓 Changelog
|
|
| 날짜 | 변경 |
|
|
|---|---|
|
|
| 2026-05-08 | Phase 1 |
|
|
| 2026-05-10 | Manual cleanup — GC root taxonomy + leak 진단 패턴 |
|