1. 개요
이 빠른 기사에서는 JVM이 도달 할 수 없지만 순환 참조를 수집하는 방법을 알아 봅니다.
먼저 다양한 유형의 GC 알고리즘을 살펴 보겠습니다. 그 후 JVM에서 순환 참조가 어떻게 처리되는지 살펴 보겠습니다.
GC는 JVM 사양의 일부가 아니며 구현 자의 재량에 달려 있다는 점도 언급 할 가치가 있습니다. 따라서 각 JVM 구현에는 다른 GC 전략이 있거나 전혀 없을 수 있습니다.
이 기사에서는 특정 JVM 구현 인 HotSpot JVM에 초점을 맞추고 있습니다. 또한 기사 전체에서 JVM 및 HotSpot JVM 용어를 상호 교환 적으로 사용할 수 있습니다.
2. 참조 카운팅
참조 계수 GC 알고리즘은 참조 계수를 각 개체와 연결합니다. 이러한 알고리즘은 해당 객체에 대한 참조 수가 0보다 크면 객체가 살아있는 것으로 간주합니다 . 일반적으로 런타임은 객체 헤더에 참조 카운트를 저장합니다.
매우 순진한 구현에서 객체에 대한 각각의 새로운 참조는 원자 참조 카운트 증가를 트리거해야합니다. 마찬가지로, 각각의 새로운 역 참조는 원자 감소를 유발해야합니다.
스위프트 프로그래밍 언어는 메모리 관리를위한 참조 횟수의 양식을 사용합니다. 또한 JVM에서 참조 횟수를 기반으로하는 GC 알고리즘이 없습니다.
2.1. 장점과 단점
긍정적 인 측면에서, 레퍼런스 카운팅은주기적인 GC 딸꾹질이 (거의) 없기 때문에 애플리케이션 라이프 사이클 전반에 걸쳐 메모리 관리 비용을 분산시킬 수 있습니다. 또한 참조 횟수가 0이되어 가비지가되는 즉시 객체를 파괴 할 수 있습니다.
참조 계산도 무료 점심이 아닙니다. 순진한 구현에서 참조 카운트를 업데이트하는 것은 원자 적으로 증가 또는 감소해야하기 때문에 비효율적 일 수 있습니다. 지연되거나 버퍼링 된 참조 계산 접근 방식과 같이 이와 관련하여 참조 계산을 더 효율적으로 만들 수있는 최적화는 거의 없습니다.
그러나 참조 카운트에는 여전히 심각한 문제가 있습니다 . 순환 참조를 회수 할 수 없습니다 .
예를 들어 객체 A 가 객체 B를 참조 하고 그 반대의 경우도 마찬가지 라고 가정합니다 . A 와 B 가 나머지 개체 그래프에서 도달 할 수 없게 되더라도 참조 횟수는 0에 도달하지 않습니다. 그들은 여전히 서로에 대한 참조를 보유하고 있기 때문입니다.
밝혀진 바와 같이, 이러한 종류의 순환 참조는 컴퓨터 과학에서 매우 일반적입니다. 예를 들어 다음과 같은 이중 연결 List을 살펴 보겠습니다. 처음에는 다른 개체에 List에 대한 참조가 있습니다.
연결 List은 개체 D 에서 도달 할 수 있으므로 수집되지 않아야하며 참조 횟수는이 예상과 일치합니다. 이제 객체 D 자체에 도달 할 수 없다고 가정합니다 .
연결 List도 현재 연결할 수 없지만 해당 구성 요소에 대한 참조 횟수는 둘 이상입니다. 따라서이 순진한 참조 계산 구현을 사용하면 런타임은이 연결 List을 가비지로 간주하지 않습니다 .
3. GC 추적
추적 수집기는 GC 루트라고하는 루트 개체 집합에서 개체를 추적하여 개체의 도달 가능성을 결정합니다 . 객체가 루트 객체에서 직접 또는 간접적으로 도달 할 수있는 경우 활성 상태로 간주됩니다. 다른 항목은 도달 할 수 없으며 수집 대상 :
간단한 추적 수집기가 작동하는 방법은 다음과 같습니다. GC 루트에서 시작하여 방문 할 회색 개체가 더 이상 남지 않을 때까지 개체 그래프를 재귀 적으로 탐색합니다. 결국 모든 흰색 물체는 도달 할 수없고 수집 대상으로 간주됩니다. 이것은 삼색 마킹 알고리즘의 간단한 묘사입니다.
GC 루트는 우리가 살아 있다고 확신하는 객체로 생각할 수 있습니다 . 예를 들어 다음은 Java 및 JVM의 일부 GC 루트입니다.
- 현재 지역 변수 또는 스택 프레임이 참조하고 있습니다. 이러한 변수는 현재 실행중인 메서드에서 사용되므로 수집하고 싶지 않습니다.
- 라이브 스레드
- 정적 변수
- 시스템 클래스 로더에 의해로드 된 클래스
- JNI 지역 및 글로벌
참조 카운팅 컬렉터와 달리 추적 컬렉터는 수집 프로세스를 주기적으로 수행합니다. 따라서 대부분의 경우 할당 및 할당이 빠르게 작동해야합니다. 그러나 GC가 시작되면 약간의 딸꾹질이있을 수 있습니다.
긍정적 인 측면에서, 이러한 GC 알고리즘은 순환 참조의 영향을받지 않습니다 . 각 개체에 대한 참조를 계산하는 대신 GC 루트에서 시작하여 개체 그래프를 순회합니다. 따라서 일부 순환 참조가 있어도 위의 다이어그램에 표시된 것처럼 도달 할 수없는 한 객체가 수집됩니다.
흥미롭게도 참조 카운팅 GC와 함께 백업 추적 수집기를 사용하는 것은 참조 카운팅에서 순환 참조를 수정하는 기존의 접근 방식 중 하나입니다.
3.1. HotSpot JVM
이 글을 쓰는 시점에서 HotSpot JVM의 모든 GC 구현 은 CMS, G1 및 ZGC를 포함한 추적 수집기 입니다. 따라서 JVM은 순환 참조 문제를 겪지 않습니다. 이것이이 기사의 핵심 내용입니다!
4. 결론
이 빠른 기사에서는 JVM이 순환 참조를 처리하는 방법을 살펴 보았습니다.
가비지 컬렉션에 대한보다 자세한 처리 방법은 가비지 컬렉션 핸드북 을 확인하는 것이 좋습니다 .