jvm의 가비지 수집 메커니즘은 가비지 수집기라고도 불리는 GC(Garbage Collection)입니다. GC의 기본 원칙: 메모리에서 더 이상 사용되지 않는 객체를 재활용합니다. GC에서 재활용하는 데 사용되는 방법을 컬렉터라고 합니다. GC는 약간의 리소스와 시간을 소비해야 하기 때문에 Java는 객체의 수명 주기 특성을 분석하여 객체를 사용합니다. GC로 인해 발생하는 Pause를 애플리케이션에 최대한 단축하기 위해 New Generation과 Old Generation에서 수집됩니다.
이 튜토리얼의 운영 환경: windows7 시스템, java8 버전, DELL G3 컴퓨터.
C 및 C++ 언어에 비해 Java의 장점 중 하나는 가비지 수집기가 함께 제공된다는 것입니다. 가비지 수집은 때때로 힙 메모리에서 도달할 수 없는 개체를 정리하는 것을 말합니다. 도달할 수 없는 개체는 즉시 재활용되지 않습니다. Java 프로그램에서 가비지 수집기의 실행은 자동이며 강제로 수행할 수 없습니다. 프로그래머가 할 수 있는 유일한 작업은 System.gc 메서드를 호출하여 가비지 수집기의 실행을 제안하는 것입니다. 그러나 실행 가능 여부와 언제 실행될지는 알 수 없습니다. 이는 가비지 수집기의 주요 단점이기도 합니다. 물론 이러한 단점은 프로그래머에게 제공되는 뛰어난 편의성으로 인해 상쇄됩니다.
가비지 수집이 필요한 이유
가비지 수집이 수행되지 않으면 메모리 공간을 재활용하지 않고 지속적으로 할당하기 때문에 메모리가 조만간 소모됩니다. 메모리가 무한하지 않다면 재활용하지 않고 임의로 할당할 수 있지만 그렇지 않습니다. 따라서 가비지 수집이 필요합니다.
JVM 런타임 데이터 영역에는 힙 영역이 있고, 힙은 거대한 개체 풀입니다. 이 개체 풀에서는 엄청난 수의 개체 인스턴스가 관리되며, 풀에 있는 개체의 일부 참조 수준은 매우 깊습니다. 자주 호출되는 인터페이스는 초당 매우 높은 속도로 개체를 생성하는 동시에 개체 간의 관계가 거대한 네트워크를 형성합니다.
Java는 무한한 메모리 환경을 만들어 왔지만 객체는 감소하지 않고 증가만 할 수 없으므로 가비지 수집이 필요합니다. 그러면 JVM은 어떤 객체를 재활용해야 하는지 어떻게 결정합니까? 어떤 것을 보관해야 합니까? 이를 위해서는 가비지 수집기라고도 불리는 GC(Garbage Collection)라고 불리는 JVM의 가비지 수집 메커니즘을 사용해야 합니다.
GC(Garbage Collection)의 기본 원리: 메모리에서 더 이상 사용되지 않는 개체를 재활용합니다. GC에서 재활용하는 데 사용되는 방법을 수집기라고 합니다. GC에서는 리소스와 시간을 소비해야 하기 때문에 Java에서는 수명을 분석한 후 사용합니다. 객체의 주기 특성을 고려하여 New Generation과 Old Generation 방식에 따라 객체를 수집하여 GC로 인해 발생하는 Pause를 애플리케이션에 최대한 단축합니다
● New Generation 객체의 컬렉션을 Minor GC라고 합니다
● 컬렉션 이전 세대의 객체를 Full GC라고 합니다
● 프로그램에서 System.gc()를 적극적으로 호출하여 강제된 GC는 Full GC입니다
객체 참조 유형이 다르고, GC는 재활용 방법이 다르며, JVM 객체 참조는 다음과 같이 나뉩니다. 네 가지 유형:
● 강력한 참조: 기본적으로 객체는 강력한 참조를 사용합니다(이 객체의 인스턴스는 다른 객체 참조가 없으며 GC에서만 재활용됩니다)
● 소프트 참조: 소프트 참조는 Java의 핵심입니다. 캐싱 시나리오에 더 적합합니다(메모리가 충분하지 않을 때만 GC됩니다)
● 약한 참조: GC 중에 GC에 의해 확실히 재활용됩니다
● 가상 참조: 가상 참조는 객체가 객체인지 여부를 아는 데만 사용되기 때문입니다. is GC
JVM의 메모리 구조에는 5가지 주요 영역이 포함됩니다. 程序计数器
、虚拟机栈
、本地方法栈
、堆区
、方法区
. 그 중 프로그램 카운터, 가상 머신 스택, 로컬 메소드 스택은 스레드로 생성되고 소멸되는 세 가지 영역이므로 이들 영역의 메모리 할당 및 재활용이 결정적이므로 재활용 문제를 고려할 필요가 없습니다. 메소드가 종료되거나 스레드가 종료되면 메모리가 자연스럽게 재활용되기 때문입니다. Java 힙 영역과 메소드 영역은 다릅니다. 메모리의 이 부분의 할당 및 재활용은 가비지 수집기가 집중해야 하는 부분입니다.
참조 카운팅은 가비지 수집기의 초기 전략입니다. 이 접근 방식에서는 힙의 각 개체 인스턴스에 참조 횟수가 있습니다. 객체가 생성되면 객체 인스턴스가 변수에 할당되고 변수 개수는 1로 설정됩니다. 다른 변수에 이 개체에 대한 참조가 할당되면 개수는 1만큼 증가합니다(a = b, 그러면 b + 1이 참조하는 개체 인스턴스의 카운터). 그러나 개체 인스턴스의 참조가 수명 주기를 초과하거나 새 값에 도달하면 개체 인스턴스의 참조 카운터가 1씩 감소합니다. 참조 카운터가 0인 모든 객체 인스턴스는 가비지 수집될 수 있습니다. 개체 인스턴스가 가비지 수집되면 참조하는 개체 인스턴스의 참조 카운터가 1씩 감소합니다.
장점: 참조 카운팅 수집기는 빠르게 실행될 수 있으며 프로그램 실행과 얽혀 있습니다. 프로그램을 장시간 중단할 필요가 없는 실시간 환경에 더욱 유리합니다.
단점: 순환 참조를 감지할 수 없습니다. 상위 개체에 하위 개체에 대한 참조가 있는 경우 하위 개체는 차례로 상위 개체를 참조합니다. 이렇게 하면 참조 횟수가 0이 될 수 없습니다.
참조 카운팅 방법을 통한 위 코드 분석:
Java 언어에서 GC Roots로 사용할 수 있는 개체는 다음과 같습니다.
● 가상 머신 스택에서 참조되는 개체(스택 프레임의 로컬 변수 테이블) ● 메서드의 클래스 정적 속성에서 참조되는 개체;
● 메소드 영역의 상수에 의해 참조되는 객체
● 로컬 메소드 스택의 JNI(네이티브 메소드)에 의해 참조되는 객체.
객체 인스턴스 1, 2, 4, 6은 모두 객체 도달 가능성, 즉 살아남은 객체와 GC에서 재활용할 수 없는 객체를 갖는다고 결론을 내릴 수 있습니다. Caprice 인스턴스 3과 5는 직접 연결되어 있지만 GC 루트는 연결되어 있지 않습니다. 즉, GC 루트가 도달할 수 없는 객체는 GC에 의해 재활용됩니다.
마킹 단계: 마킹 과정은 실제로 앞서 소개한 도달성 분석 알고리즘의 과정입니다. 모든 GC Roots 객체를 순회하고 일반적으로 객체 헤더에 GCRoots 객체에서 도달할 수 있는 객체에 표시를 합니다. , 도달 가능한 객체로 기록합니다.
청소 단계: 정리 프로세스는 힙 메모리를 순회하는 것입니다. 개체 헤더 정보를 읽어 도달 가능한 개체로 표시되지 않은 개체가 발견되면 재활용됩니다.
위 그림은 mark/clear 알고리즘의 개략도입니다. mark 단계에서 객체 B는 객체 GC Root 1에서 접근할 수 있고, 객체 E는 객체 B에서 접근할 수 있습니다. 따라서 GC Root에서 접근할 수 있습니다. 1부터 B와 E까지 모두 도달 가능합니다. 마찬가지로 객체 F, G, J 및 K는 모두 정리 단계에서 도달 가능한 객체이며, 도달할 수 없는 모든 객체는 재활용됩니다.
가비지 컬렉터가 GC를 수행할 때 모든 Java 실행 스레드를 중지해야 합니다("Stop The World"라고도 함). 그 이유는 마킹 단계에서 도달성 분석을 수행할 때 개체 참조 관계가 계속 변경될 수 없기 때문입니다. 그렇지 않으면 도달성 분석 결과의 정확성을 보장할 수 없습니다. 표시가 지워질 때까지 애플리케이션 스레드 실행이 재개되지 않습니다.표시/지우기 알고리즘 단점: ● 효율성 문제
표시와 지우기의 두 단계는 모두 메모리의 개체를 순회해야 하고 메모리의 개체를 여러 번 순회해야 하기 때문에 그다지 효율적이지 않습니다. 메모리 인스턴스 수가 매우 많아 시간이 많이 걸리며, GC 중에 애플리케이션을 중지해야 하므로 사용자 경험이 매우 저하됩니다. ●
공간 문제
표시가 지워진 후 많은 수의 불연속적인 메모리 조각이 생성됩니다(위 그림에서 볼 수 있듯이). 메모리 공간 조각이 너무 많으면 필요한 더 큰 개체를 찾을 수 없게 될 수 있습니다. 프로그램 실행 중에 다른 가비지 수집 작업을 미리 트리거할 만큼 충분한 연속 메모리가 할당됩니다.
복사 알고리즘은 매번 전체 절반 영역의 메모리를 재활용하므로 표시된 개체를 순회하는 시간이 줄어듭니다. 사용된 영역 개체를 지울 때 순회할 필요가 없으며 전체 영역 메모리가 직접 지워지고 살아남은 개체가 삭제됩니다. 객체는 예약된 영역에 복사되며, 영역도 주소순으로 저장되므로 메모리 조각화 문제가 해결됩니다. 객체 메모리 할당 시 메모리 조각화와 같은 복잡한 문제를 고려할 필요가 없습니다. .
복사 알고리즘의 단점:
복사 알고리즘은 간단하고 효율적이며 마크 앤 클리어 알고리즘의 낮은 효율성과 메모리 조각화 문제를 최적화합니다. 단점이 있습니다.
● 메모리를 원본의 절반으로 줄입니다. 크기, 메모리 공간의 절반 낭비, 비용이 너무 높습니다.
● 객체의 생존율이 매우 높으면 극단적인 경우 객체 생존율을 100%로 가정하면 살아남은 모든 객체를 복사해야 합니다. , 시간 비용도 무시할 수 없습니다.
Mark-Collate Algorithm 이 알고리즘은 mark/clear 알고리즘과 매우 유사합니다. 실제로 mark/collate 알고리즘의 표시 프로세스는 여전히 mark/clear 알고리즘과 동일합니다. 그러나 후속 단계는 Recyclable 객체와 직접적인 관련이 없지만 살아남은 객체는 모두 한쪽 끝으로 이동한 다음 끝 가장자리 이후의 메모리를 직접 지웁니다.
재활용이 가능한 물건들은 재활용 후 깨끗하게 정리되고, 살아남은 물건들은 규칙에 따라 메모리에 정리되는 모습을 볼 수 있습니다. 이런 방식으로 새 객체에 메모리를 할당할 때 jvm은 메모리의 시작 주소만 보유하면 됩니다. 마크/구성 알고리즘은 마크/클리어 알고리즘의 메모리 조각화 문제를 보완하고 복사 알고리즘의 메모리를 절반으로 줄이는 데 드는 높은 비용을 제거합니다.
마킹/정리 단점:
● 비효율성: 살아남은 객체를 마킹해야 할 뿐만 아니라 살아남은 모든 객체의 참조 주소도 함께 구성해야 하는데 이는 복사 알고리즘만큼 효율적이지 않습니다.
세대별 수집 알고리즘의 개념은 객체의 다양한 생존 주기에 따라 메모리를 여러 블록으로 나누는 것입니다. 일반적으로 Java 힙은 새로운 세대와 Old 세대(영구 세대도 있는데 HotSpot의 독특한 구현이다. 다른 가상 머신 구현에는 이 개념이 없다. 영구 세대의 수집 효과는 매우 나쁘다. 일반적으로 영구 세대의 가비지 수집은 거의 없다. 수행) 각 시대의 특성에 따라 가장 적합한 수집 알고리즘을 사용할 수 있도록 하였습니다.
특징:
새로운 세대: 빠르게 태어나고 사라지며 생존 시간이 매우 짧습니다. 복제 알고리즘을 사용하여 수집
Old Generation: 여러 Minor GC 후에도 생존하고 긴 생존 기간을 갖습니다. 표시/지우기 알고리즘 또는 표시/구성 알고리즘을 사용하여 이전 세대를 수집합니다
신세대의 모든 가비지 수집에서는 많은 수의 객체가 죽고 소수만이 살아남는다는 사실을 발견합니다. 따라서 복사 알고리즘을 사용하여 신세대만 재활용합니다. 적은 수의 개체를 복사하는 데 비용이 필요합니다.
구세대의 개체 생존율이 높고 복사 알고리즘을 사용하는 경우 적합하지 않습니다. , 할당 보장을 위한 추가 공간이 없으므로 재활용을 위한 표시/정리 알고리즘 또는 표시/조합 알고리즘을 사용합니다.
새 세대의 개체는 "살다가 죽는다". GC가 발생할 때마다 많은 수의 개체가 죽고 소수가 살아남는 복제 알고리즘이 사용됩니다. 신세대는 Eden 영역과 Survivor 영역(Survivor from, Survivor to)으로 구분되며, 크기 비율은 기본적으로 8:1:1입니다.
Old Generation 객체의 경우 객체 생존율이 높고 할당 보장을 위한 추가 공간이 없기 때문에 mark-clear 또는 mark-complement 알고리즘을 사용합니다.
새로 생성된 객체는 Eden 영역에 먼저 진입합니다. Eden 영역이 가득 차면 Survivor from이 사용됩니다. Survivor from도 가득 차면 Minor GC(신세대 GC)가 수행되고 Eden 및 Survivor from에 남아 있는 객체가 복사됩니다. to로, 그리고 나서 Eden과 Survivor from을 클리어합니다. 이때 원래의 생존자는 to의 새로운 생존자가 되고, 원래의 생존자는 from의 새로운 생존자가 됩니다. 복사 시 Survivor to가 살아남은 객체를 모두 수용할 수 없는 경우 Old Generation의 할당 보증을 기반으로 해당 객체를 Old Generation으로 복사합니다(은행의 대출 보증과 유사). (이전 세대) GC가 수행됩니다.
큰 객체가 Old Generation에 직접 들어갑니다. JVM
-XX:PretenureSizeThreshold에 매개변수 구성이 있는데, 이 설정 값보다 큰 객체가 Old Generation에 직접 들어가는 것을 방지하는 것이 목적입니다. 에덴과 생존자 지역.
장기 생존 개체가 구세대로 들어갑니다. JVM은 각 개체에 대한 개체 연령 카운터를 정의합니다. Eden이 탄생하고 첫 번째 Minor GC를 통과한 후에도 개체가 여전히 생존하고 생존자가 수용할 수 있는 경우 해당 개체는 다음 세대로 이동됩니다. 생존자와 그 나이는 1로 설정됩니다. Minor GC에서 살아남지 못한 경우 age는 1씩 증가합니다. age가 특정 수준에 도달하면(기본값은 15세이며 XX:MaxTenuringThreshold를 통해 설정할 수 있음) Old Generation으로 이동됩니다. . 그러나 JVM은 Old Generation으로 승격되기 전에 age가 최대 age에 도달해야 한다고 항상 요구하지는 않습니다. 생존자의 절반 이상이면 x보다 크거나 같은 모든 개체는 이전 세대에 직접 입력되며 최대 수명 요구 사항까지 기다릴 필요가 없습니다.
세대 재활용:
우리는 object1을 사용하여 세대 가비지 수집 알고리즘의 재활용 궤적을 설명합니다.
1. Object1이 새롭게 탄생하여 신세대 에덴 지역에서 탄생했습니다.
2. object1은 아직 살아 있고 현재로서는 아직 새로운 세대에 있습니다.
3. object1은 아직 살아있습니다. 이때 object1은 복사 알고리즘을 통해 ToSuv 영역으로 이동됩니다.
4. Minor GC, object1은 아직 살아있습니다. 이때 생존자 중 object1과 같은 나이의 개체가 생존자 중 절반에 도달하지 않았으므로 이때 fromSuv와 Tosuv 영역이 교환됩니다. 복사 알고리즘을 통해 살아남은 개체는 Tosuv로 이동됩니다.
5. Minor GC, object1은 아직 살아있습니다. 이때 생존자 중 object1과 동일한 연령의 개체가 생존자 중 절반 이상에 도달했으며(toSuv 영역이 가득 찼음) object1이 이동되었습니다. Old Generation 영역으로.
6. object1이 일정 시간 동안 생존한 후, 이때 object1이 GcRoots에 도달할 수 없는 것으로 확인되었으며, 이때 Old Generation 공간 비율이 임계값을 초과하여 majorGC가 발생했습니다(또한 고려될 수 있음). fullGC로 사용하지만 가비지 수집기가 필요합니다.) Contact), object1은 이때 재활용됩니다. fullGC는 세상을 멈추게 할 것입니다.
위의 새로운 세대에서는 개체의 나이에 대해 언급했습니다. 개체는 생존자 상태에서 살아남으며 Old 세대에 대한 과도한 영향을 피하기 위해 즉시 Old 세대 개체로 승격되지 않습니다. 다음과 같은 조건이 승격될 수 있습니다:
1. 마이너 GC 이후 생존자 영역에서 살아남는 개체의 연령은 +1이 됩니다.(기본값) 15를 초과하면 Old Generation으로 이전됩니다.
2. 동적 객체, 생존자 공간에 있는 같은 연령의 모든 객체의 크기를 합친 크기가 생존자 공간의 절반보다 크면 해당 연령보다 크거나 같은 등급의 객체가 Old Generation에 직접 들어갈 수 있습니다.
위 내용은 jvm의 가비지 수집 메커니즘은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!