세대 단위 컬렉션 이론
- 대다수 객체는 일찍 사라짐(약한 세대 가설)
- GC과정에서 살아남은 횟수가 늘어날 수록(앞으로도) 생존 가능성이 높아짐(강한 세대 가설)
- 다른 세대에 속한 객체간 참조는 같은 세대에 속한 객체간 참조보다 훨씬 작음(세대 간 참조 가설)
- 핫스팟 VM에서 에덴과 생존자 공간비율을 보통 8:1
- IBM 연구에 따름(보통 첫 GC에 대락 98% 객체가 소멸)
- 10%는 메모리 파편화 방지를 위해 활용(Overhead)

Young gereration
- Eden
- 객체 생성 직후 저장되는 영역
- Minor GC 발생 시 Survivor 영역으로 이동
- Copy & Scavenge 알고리즘
- Survivor 0, 1
- Minor GC 발생 시 Eden, S0 에서 살아남은 객체는 S1으로 이동
- S1에서 살아남은 객체는 Old 영역으로 이동
- age bit 사용(참조계수)
Old generation
- Old
- Young generation 영역에서 소멸하지 않고 남은 객체들이 사용하는 영역
- Full GC 발생 시 개체 회수
- 시간이 오래 걸린다
- Mark & Compact 알고리즘
Permanent
- Metaspace(Java 8)
- 로드되는 클래스, 메소드 등에 관한 메타 정보 저장(자동확장 가능)
- Java Heap이 아닌 Native 메모리 영역 사용
- 리플렉션 클래스 로드 시 사용(Spring)
대표적인 GC 알고리즘 - Mark and Sweep
- 1960년대 제안된 가장 기본적 GC 알고리즘으로 후속 알고리즘의 토대
- 1단계 표시(Mark, 회수 대상 판단), 2단계 회수(Sweep)방식
- 단점
- 효율이 일정하지 않음. 특히 힙이 많이 채워져 있을 경우 작업 효율이 매우 떨어진다.
- 메모리 파편화에 따른 비효율 문제
대표적인 GC 알고리즘 - Mark and Copy
- 1969년 mark and sweep 을 보완하기 위해 로버트 페니첼이 제안
- 가용 메모리 공간을 둘로 나눈 후 한쪽만 사용(S0, S1)
- 한 공간에서 mark and sweep 실시 후 파편화된 조각(살아남은 소수의 인스턴스들)을 다른 공간으로 복사
- 사용했던 공간을 모두 비우는 식으로 Sweep
- 단점
- 가용 메모리 공간이 절반으로 줄어듬
- 이후 개선이 8(가용공간):1:1 로해서 2를 1:1로 반나눔
- 1989년 엔드류 아펠의 제안으로 개선
대표적인 GC 알고리즘 - Mark and Compact
- 생존한 객체 많을 수록 복사해야할 인스턴스가 늘어나는 mark and sweep 단점 극복을 위해 1974년 에드워드 루더스가 제안
- 1단계 mark후 2단계에서 생존 객체를 한쪽 구석으로 모으고(이동) 나머지만 Sweep
- 단점
- 살아남는 객체 많을 수록 부담 크게 증가
- 인스턴스 이동 과정에서 응용 프로그램의 연산이 일시정지(stop the world)
도달 가능성 분석
- 도달 가능성 분석 Reachability Analysis 알고리즘에 기초해 회수 대상 인스턴스를 판단
- GC 루트 객체들을 기점으로 참조하는 다른 객체들을 탐색하는 방식
GC 루트 객체가 될 수 있는 것들
- JVM stack frame 지역변수 테이블에서 참조하는 객체(현재 실행 중인 메서드)
- Synchronized 키워드로 잠겨 있는 객체
- JNI가 참조하는 객체
- 메서드 영역에서 클래스 정적 필드로 참조하는 객체
- 메서드 영역에서 상수로 참조되는 객체
- JVM 내부에서 사용되는 참조
클래식 GC 종류 일부
- Serial
- 단일 스레드로 작동. 회수가 끝날 때까지 모두 멈춤
- 간단하고 효율적이며 알고리즘 수준에서 리소스 사용량 적음
- ParNew
- 시리얼 컬렉터를 병렬처리
- Parallel scavenge
- 사용자 코드 처리 실행 효율을 극대화를 목표로 설계
클래식 GC 종류
- CMS(Concurrent Mark Sweep) GC
- Java 9부터 사용하지 않다가 Java 14에서 G1GC를 지원하고자 완전히 제거
- G1(Garbage First) GC
- 4GB 이상 대용량 Heap 메모리를 사용하는 멀티스레드 기반 응용 프로그램에 특화된 GC
- Heap을 영역(1~32MB)단위로 분할한 후 멀티스레드로 스캔
G1 GC
- 서버용 응용 프로그램에 집중한 GC
- JDK 9 부터 기본 GC
- JVM 힙을 세대단위가 아닌 독립 영역으로 구분해 관리하는 것이 특징
- Heap을 영역(1~32MB)단위로 분할한 후 멀티스레드로 스캔
- 힙의 모든 영역을 회수 집합(CSet, Collection Set)에 포함시켜 영역단위 처리
- 가장 쓰레기가 많은 영역을 파악
- 회수 시 가장 득이 되는 영역 파악
객체 메모리 레이아웃과 해시코드

- Hash code는 Object.hashCode() 함수가 호출되는 시점에 계산
- 나이는 GC에서 살아남은 횟수
- Lock flag를 객체를 중심으로 멀티스레드 환경에서 경쟁조건이 발생하는 문제를 해결하기 위한 것
C계열은 klass Java계열은 clazz
MD-5 같은 해시함수를 단방향 암호화 수단으로 안쓰는건 이미 역추출하는 알고리즘같은게 존재해서 위험하기때문
핫스팟 VM 객체 Lock flag
| Lock flag | 상태 | Mark word 저장 정보 |
|---|---|---|
| 00 | Lightweight locking | Lock 레코드(스핀락 동기화) |
| 01 | Unlock | 객체의 Hash code 및 나이 |
| 01 | Biased locking | 스레드, ID, 타임스탬프, 객체 나이 |
| 10 | Heavyweight locking | 뮤텍스로 동기화 |
| 11 | GC mark | GC가 객체 이동 중 |
Object 클래스
- Java의 모든 클래스의 부모 클래스
- equals()
- 매개변수로 전달된 참조자와 this가 가리키는 대상이 같은 값인지 값만 비교(shallow copy 문제)
- toString()
- 클래스명@해시코드
’같다’라는 의미
- 해시코드가 같은 인스턴스는 존재하지 않음
- 가리키는(참조하는) 대상이 같은 경우
- 인스턴스가 가진 값과 관련 없다
- 인스턴스 a, b, c는 모두 같은 클래스의 인스턴스
- 같은 클래스의 인스턴스라해도 각각은 독립적
- (모든) 필드의 값이 같으면 논리적으로 같음. 내용이 같음
- 클래스가 같고 인스턴스값(메모리에 저장된 내용)까지 같은 경우
equals()의 기본 동작은 참조값만 비교한다! 내용비교를 하고싶으면 오버라이딩을 하는 것.
동등성(Equality)와 동일성(Identity)
- 두 인스턴스를 비교해 같은 클래스 인스턴스이며 내용도 일치하는지 비교하는 것이 동등성
- Deep copy 처럼 두 인스턴스 내용을 비교
- 동일성은 같은 한 인스턴스에 대한 참조자인지 값을 비교
- Shallow copy 처럼 참조자 값만 비교
- 한 인스턴스를 가리키는 것인지 확인