Files
2nd/10_Wiki/Topics/Programming & Language/GC Root.md
T
Antigravity Agent f8b21af4be Wiki cleanup: error-doc removal, dedup merge, link normalization
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>
2026-05-20 23:52:15 +09:00

6.0 KiB

id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
id title category status canonical_id aliases duplicate_of source_trust_level confidence_score verification_status tags raw_sources last_reinforced github_commit tech_stack
wiki-2026-0508-gc-root GC Root 10_Wiki/Topics verified self
Garbage Collection Root
GC 루트
Root Set
none A 0.9 applied
gc
jvm
memory
runtime
2026-05-10 pending
language framework
Java/Kotlin 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)

# 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+)

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 진입 회피

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)

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)

// JNI: global ref 는 명시적으로 free 해야 함
jobject globalRef = (*env)->NewGlobalRef(env, localObj);
// ... 사용 ...
(*env)->DeleteGlobalRef(env, globalRef);  // 매 빠뜨리면 영구 leak

6. Static field 로 의도된 long-lived root

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 활성화

# 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 찾기

./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 진단 패턴