Java/JVM
[JVM 밑바닥까지 파헤치기] 3-1. 가비지 컬렉터와 메모리 할당 전략: 회수
noahkim_
2024. 12. 19. 23:06
저우즈밍 님의 "JVM 밑바닥까지 파헤치기" 책을 정리한 포스팅 입니다.
1. 참조
- 힙에 있는 객체의 메모리 주소를 가리키는 값
- ✅ GC는 참조 그래프를 따라 GC Root로부터 도달 가능한지를 기준으로 객체의 생존 여부를 결정함
타입
| 참조 타입 | 정의 및 설명 | GC 수집 시점 | 주요 용도 |
| Strong Reference | 일반적인 객체 참조 | ❌ | 일반 객체 참조 |
| Soft Reference | 메모리 부족 시에만 수집되는 참조 | ⚠️ 메모리 부족 시 | 캐시 |
| Weak Reference | 강한 참조가 사라지면, 다음 GC에 바로 수거 대상이 되는 참조 | ✅ | 메모리 누수 방지 |
| Phantom Reference | 객체가 완전히 GC 대상이 된 후 감지하기 위한 참조 | ✅ | 객체 이벤트 감지 |
예시) Soft Reference
더보기
SoftReference<String> softRef = new SoftReference<>(strongRef);
예시) Weak Reference
더보기
String strong = new String("I am strong");
WeakReference<String> weakRef = new WeakReference<>(strong);
strong = null;
System.gc();
WeakHashMap
Map<Object, String> map = new WeakHashMap<>();
Object key = new Object();
map.put(key, "value");
key = null;
System.gc();
System.out.println(map.size());
// 0 이 될 수 있음
- 일반 HashMap은 외부에서 key의 strong reference가 해제되어도 Map 내부에서 strong reference로 보관
- ⚠️ 관련 객체가 GC에 의해 수거되지 않음
- ➡️ key를 WeakReference로 보관하므로 외부 strong reference가 해제되면 key와 entry가 GC에 의해 수거됨
예시) Phantom Reference
더보기
ReferenceQueue<String> queue = new ReferenceQueue<>();
PhantomReference<String> phantomRef = new PhantomReference<>(new String("I am phantom"), queue);
System.gc(); // GC 호출
// queue를 통해 팬텀 참조 이벤트 확인 가능
- GC가 객체를 실제 메모리에서 제거하기 직전에 ReferenceQueue에 Phantom Reference를 넣어줌
- ⚠️ get() 불가 (항상 null값)
- ✅ 리소스 해제 작업 및 삭제 후 처리 로직에 사용됨
2. 힙 영역 회수
- 메모리 회수가 동적으로 이루어짐
- ✅ 힙을 청소하려면, 어떤 객체가 살아있고 죽어있는지 판단해야 함
알고리즘
| 항목 | 참조 카운팅 알고리즘 |
도달 가능성 분석 알고리즘
|
| 기본 원리 | 객체의 참조 카운터에 따라 살아있는지 판단 |
GC Root에서 객체 참조 그래프를 따라가며 도달 여부 판단
|
| 로직 | 참조 시 +1, 참조 해제 시 -1, 카운터가 0이면 수집 |
GC Root와 연결되지 않은 객체는 수집 대상
|
| 문제점/제약 | 순환 참조 시 수집 불가 |
순환 참조도 안전하게 수집 가능
|
| 부가 처리 | 없음 |
finalize() 호출 대상은 F-Queue에 넣고 나중에 처리
|
| 객체 부활 가능성 | 불가능 |
finalize() 중 객체가 참조를 다시 얻으면 1회 부활 허용
|
| 사용 예 | Objective-C, 일부 C++ 스마트 포인터 등 |
JVM 기반 언어 (Java, Kotlin 등)
|
3. 메서드 영역 회수
- JDK 12부터 메서드 영역 회수 공식 지원
- ✅ ex) 리플렉션 기반 바이트코드 생성 라이브러리 (CGLib, Proxy)
- ✅ ex) OSGi, JSP, 사용자 정의 ClassLoader 환경 등
회수 조건
- 해당 클래스의 클래스 로더가 GC됨
- 해당 클래스의 모든 인스턴스가 GC됨
- Class 객체/리플렉션 메서드에 대한 참조 없음
JVM 옵션
| 옵션 | 설명 |
| -Xnoclassgc | 클래스 언로딩 비활성화 |
| -verbose:class | 클래스 로드 로그 출력 |
| -Xlog:class+load=info | 클래스 로드 로그 |
| -Xlog:class+unload=info | 클래스 언로드 로그 |