Java에서 메모리 관리에는 메모리 할당 (Java 객체 생성시)과 메모리 재활용의 두 가지 측면이 포함됩니다. 작업의 두 측면 모두 JVM에 의해 자동으로 완료되므로 Java 프로그래머의 학습이 어려워지고 C/C ++와 같은 직접 메모리를 직접 작동하는 위험을 피합니다. 그러나 메모리 관리는 JVM에 의해 전적으로 처리되기 때문에 많은 Java 프로그래머가 더 이상 메모리 할당에 관심이 없기 때문에 많은 프로그램이 비효율적이고 메모리를 소비합니다. 따라서 Java 프로그래머는보다 효율적인 프로그램을 작성하고 제한된 메모리를 최대한 활용하려면 결국 JVM을 이해해야합니다.
1. 자바의 기억에
먼저 코드를 예를 들어 봅시다.
사람. 자바
패키지 테스트; import java.io.serializable; 공개 클래스 개인을 구현하십시오. {static final long serialversionuid = 1L; 문자열 이름; // 이름을 가진 친구; // friends public person () {} public person (string name) {super (); this.name = 이름; }} test.java
패키지 테스트; 공개 클래스 테스트 {public static void main (String [] args) {person p1 = new Person ( "Kevin"); 사람 P2 = 새로운 사람 ( "비"); Person P3 = 새로운 사람 ( "Sunny"); p1.friend = p2; p3 = p2; p2 = null; }} Test.java의 주요 측면에서 객체 참조를 기본 메소드에서 시작하는 객체 참조 다이어그램으로 그리면 이와 같습니다 (정점은 객체 및 참조이며, 지시 된 가장자리는 참조 관계입니다).
프로그램이 실행되면 지시 된 그래프로 간주 된 후 세 가지 유형으로 나눌 수 있습니다.
1) 달성 가능한 상태 : 객체가 생성 된 후 하나 이상의 참조 변수가이를 나타냅니다. 지시 된 그래프에서는 시작 정점에서 객체로 이동할 수 있으며 접근 가능한 상태입니다.
2) 복구 가능한 상태 : 프로그램의 객체에 더 이상 참조 변수가없는 경우 먼저 복원 가능한 상태로 들어가고 현재는 지시 된 그래프의 시작 정점에서 객체로 이동할 수 없습니다. 이 상태에서 시스템의 쓰레기 수집 메커니즘은 물체가 차지하는 메모리를 재활용 할 준비가되었습니다. 재활용하기 전에 시스템은 최종화 () 메소드를 호출하여 리소스를 정리합니다. 리소스가 정렬 된 후 둘 이상의 참조 변수가 회수되면 객체는 다시 접근 가능한 상태가됩니다. 그렇지 않으면 도달 할 수없는 상태로 들어갑니다.
3) 도달 할 수없는 상태 : 객체의 모든 연관성이 차단되고 시스템이 finalize () 메소드를 호출하여 리소스를 정리하기 위해 여전히 객체에 도달 할 수없는 상태를 만들지 않으면 객체가 영구적으로 참조를 잃고 도달 할 수없는 상태가되며 시스템은 객체가 차지하는 자원을 진정으로 재활용합니다.
위의 세 상태의 전이 다이어그램은 다음과 같습니다.
2. 4 Java의 개체에 대한 참조
1) 강력한 참조 : 객체를 만들고이 객체를 변수에 직접 할당하십시오 (예 : 사람 person = new Person) ( "Sunny"); 시스템 리소스가 아무리 타이트하더라도, 강력한 참조 객체는 앞으로 다시 사용되지 않더라도 재활용되지 않을 것입니다.
2) 소프트 참조 : Softreference 클래스 (예 : 소프트로 회의 <person> p = New Softreference <person>) (새로운 사람 ( "Rain")); 메모리가 매우 빡빡하면 재활용되며 다른 시간에 재활용되지 않으므로 사용하기 전에 재활용되었는지 여부를 결정해야합니다.
3) 약한 참조 : 약한 회의 클래스를 통해 구현 됨 : 예를 들어 : 약점 회의 <person> p = new 약점 <person> (새로운 사람 ( "Rain")); 메모리가 충분한 지 여부에 관계없이 시스템은 쓰레기 수집 중에 확실히 재활용됩니다.
4) 가상 인용구 : 혼자서 사용할 수 없으며 주로 수집 된 쓰레기의 상태를 추적하는 데 사용됩니다. Phantomreference 클래스 및 참조 대기열 참조 Quesure 클래스를 통해 구현 : 예를 들어 :
패키지 테스트; import java.lang.ref.phantomreference; import java.lang.ref.ref.reforequeue; public class test {public static void main (String [] args) {// 객체 사람을 만듭니다 = 새로운 사람 ( "sunny"); // 참조 대기열 참조 Queue referenceQueue <person> rq = new ReferenceQueue <person> (); // 가상 참조를 만들고,이 가상 참조를 사람 객체에 대한 참조 참조 <person> pr = new phantomreference <person> (person, rq); // 참조 변수와 사람의 객체를 정착시킵니다. 참조 person = null; // 가상 참조로 참조 된 객체를 꺼내려고 노력하십시오. // 프로그램이 가상 참조를 통해 참조 된 객체에 액세스 할 수 없으므로 여기의 출력은 null system.out.println (pr.get ())입니다. // 강제 쓰레기 수집 시스템 .gc (); System.Runfinalization (); // 가상 참조의 객체가 재활용되면 가상 참조가 참조 대기열에 들어가기 때문에 // 큐에 큐에 입력 된 참조를 사용하여 pr과 비교하고 true system.out.println (rq.poll () == pr); }}실행 결과 :
3. Java Garbage Collection 메커니즘
실제로, Java Garbage Collection은 주로 두 가지를 수행합니다. 1) 메모리 재활용 2) 탈퇴
3.1 쓰레기 수집 알고리즘
1) 일련의 재활용 (하나의 CPU) 및 병렬 재활용 (다중 CPU가 유용함) : 일련의 재활용은 시스템에 얼마나 많은 CPU가 있든 항상 쓰레기 수집 작업을 수행하는 것이 항상 하나의 CPU 일 뿐이라는 것을 의미합니다. 병렬 재활용은 전체 재활용 작업을 여러 부분으로 나누는 것을 의미하며, 각 부분은 하나의 CPU가 책임을 지므로 여러 CPU가 병렬로 재활용 될 수 있습니다. 병렬 재활용은 실행이 매우 효율적이지만 복잡성을 증가 시키며 메모리의 무작위 증가와 같은 부작용도 있습니다.
2) 동시 실행 및 응용 프로그램 중지 : 이름에서 알 수 있듯이 쓰레기 수집 방법은 쓰레기 수집을 수행하는 동안 응용 프로그램 서스펜션을 유발합니다. 동시 실행의 쓰레기 수집은 응용 프로그램과 충돌을 해결해야하기 때문에 응용 프로그램이 일시 중지되지는 않지만 (응용 프로그램은 쓰레기 수집 과정에서 객체를 수정할 수 있음), 쓰레기 수집의 동시 실행의 시스템 오버 헤드보다 더 높고, 실행할 때 더 많은 메모리가 필요하기 때문입니다.
3) 압축 및 비 압축 및 복사 :
compression (mark-compression = mark-clear + compression)를 지원하는 쓰레기 수집기는 도달 가능한 모든 객체를 함께 재배치 한 다음 이전에 점유 된 모든 메모리를 재활용하여 메모리 조각화를 줄입니다.
② 압축되지 않은 쓰레기 수집기 (마크 클리어)는 두 번 횡단해야합니다. 처음으로 도달 가능한 모든 객체에 처음 액세스하고 도달 가능한 상태로 표시 할 때. 두 번째로는 전체 메모리 영역을 용이하게하고 도달 할 수없는 상태로 표시되지 않은 객체를 재활용합니다. 이 재활용 방법은 압축되지 않으며 추가 메모리가 필요하지 않지만 두 개의 횡단이 필요하면 단편화를 생성합니다.
the 쓰레기 수집기 복사 : 힙 메모리를 두 개의 동일한 공간으로 나누고 루트에서 각 관련 도달 가능한 객체에 액세스하고 (이전 지시 된 그래프의 시작 정점과 유사) 공간 A에서 공간 B에서 공간 B에서 모든 도달 가능한 물체를 복사 한 다음 한 번에 공간을 재활용하십시오. 이 알고리즘의 경우, 모든 도달 가능한 객체에만 액세스 할 필요가 있기 때문에, 도달 가능한 모든 객체를 복사하고, 전체 공간을 직접 재활용하고, 도달 할 수없는 물체를 전혀 무시하고, 공간을 가로 지르는 비용은 작지만 엄청난 복사 비용과 더 많은 메모리가 필요합니다.
3.2 힙 메모리의 세대 재활용
1) 세대 재활용의 기초 :
while 객체의 생존 시간의 길이 : 대부분의 물체는 어린 시절에 재활용됩니다.
2) 힙 메모리 생성 :
① 젊은 세대 :
종 종 메커니즘을 재활용 : 물체의 수는 작기 때문에 복제 및 재활용이 사용됩니다.
consolidation 지역 : 1 개의 Eden 지역과 2 개의 생존자 지역으로 구성됩니다. 두 생존자 영역은 동시에, 하나는 물체를 저장하고 다른 하나는 비어 있습니다. 젊은 세대 쓰레기 수집이 수행 될 때마다 에덴의 접근 가능한 물체가 지역으로 복사되며, 오래된 개체 중 일부는 노년기로 복사되며, 에덴과 우주에서 우주에서 공간에서 공간에서 공간에서 공간에서 공간에서 공간에서 원본이됩니다.
ⅲ 객체 출처 : 대부분의 객체는 먼저 에덴 영역에 할당되며 일부 큰 객체는 구식에 직접 할당됩니다.
ⅳ 재활용 주파수 : 대부분의 젊은 세대 물체는 도달 할 수없는 상태로 빠르게 들어가기 때문에 재활용 주파수가 높고 재활용 속도가 빠릅니다.
율 - 폴드 세대 :
gccubing 메커니즘 : 마크 압축 알고리즘을 사용하여 복구하십시오.
ⅱ 객체의 원천 : 1. 큰 물체는 직접 노년기에 들어갑니다.
2. 젊은 세대에서 생존 시간이 긴 도달 가능한 물체의 재활용 빈도 : 객체가 거의 없기 때문에 실행 주파수는 높지 않으며 완료하는 데 오랜 시간이 걸립니다.
율의 한 세대 :
pperpose : 클래스, 메소드 및 기타 정보를로드하는 데 사용됩니다. 기본값은 64m이며 재활용되지 않습니다. ABJECT 출처 : 예 : AOP 동적 생성 클래스와 같은 최대 절전 모드 및 스프링과 같은 프레임 워크의 경우 종종 많은 동적 프록시 클래스를 생성하므로 더 많은 영구적 인 생성 메모리가 필요합니다. 따라서 우리는 종종 java.lang.outofMemoryError : hibernate를 디버깅 할 때 Permgen 공간 오류를 만납니다. 이것은 영구 생성 메모리 소진으로 인한 오류입니다.
ⅲ 재활용 빈도 : 재활용되지 않습니다
3.3 일반적인 쓰레기 수집가
1) 직렬 재활용기 (하나의 CPU 만 사용) : 젊은 세대는 직렬 사본 알고리즘을 사용합니다. 구식은 직렬 마크 압축 알고리즘 (3 단계 : Mark Mark -Clear Sweep - Compress Compract)을 사용하면 프로그램이 재활용 기간 동안 일시 중지됩니다.
2) 병렬 재활용기 : 젊은 세대에 사용되는 알고리즘은 직렬 재활용기와 동일하지만 멀티 CPU 병렬 처리 만 추가합니다. 구식의 처리는 직렬 재활용기의 처리와 정확히 동일하며 여전히 단일 스레드입니다.
3) 병렬 압축 수집기 : 젊은 세대의 처리는 병렬 수집기의 처리와 정확히 동일한 알고리즘입니다. 그러나 구식에는 다른 알고리즘이 사용되며, 실제로는 다른 영역으로 나누어지고 라벨링 및 압축 알고리즘으로 나뉩니다.
① 오래된 고정 된 지역으로 나뉘 었습니다.
② 마크 스테이지 (다중 스레드 평행), 마킹 도달 가능한 물체;
③ 요약 단계 (직렬 실행). 왼쪽에서 수치 값 (낮은 물체 밀도)에 도달하는 영역을 찾으면이 영역과 오른쪽 영역이 압축되어 회수됩니다. 왼쪽 끝은 밀도가 높은 영역 ④ 콤팩트 스테이지 (다중 스레드 병렬)이며로드해야 할 영역을 식별하고 데이터를 이러한 영역에 병렬로 복사합니다. 이 과정 후에는 구식의 한쪽 끝에 많은 활성 물체가 있고 다른 쪽 끝에는 큰 공간이 있습니다.
4) 동시 식별 - 청소 및 재활용 (CMS) : 젊은 세대의 처리는 병렬 재활용기의 처리와 정확히 동일한 알고리즘입니다. 그러나 구식에는 다른 알고리즘이 사용되지만 마크 청소 알고리즘은 여전히 사용됩니다.
① 초기 식별 (프로그램 일시 정지) : 직접 참조 된 객체 (1 단계 개체)를 표시합니다.
② 동시 식별 (프로그램 실행) : 1 단계 객체를 통해 다른 도달 가능한 개체를 찾으십시오.
③ 리마크 (프로그램 일시 정지) : 동시성으로 인해 놓칠 수있는 멀티 스레드 병렬 리마킹 객체 (간단히 말하면, 반사 방지).
④ 동시 청소 (프로그램 실행)
4. 메모리 관리 팁
1) 직접 수량을 사용하십시오 (예 : String javast =) "초등학교 도제의 성장 과정";
2) StringBuilder 및 StringBuffer를 사용하여 문자열 연결 및 기타 작업을 수행하십시오.
3) 쓸모없는 물체를 가능한 빨리 풀어 놓으십시오.
4) 정적 변수를 최대한 적게 사용하십시오.
5) 일반적으로 사용되는 객체 : 오픈 소스 오픈 소스 캐시 (예 : Oscache, ehcache)를 사용하여 구현할 수 있습니다.
6) finalize () 메소드를 사용하지 마십시오.
7) 필요한 경우 소프트 참조 소프트로를 사용하는 것을 고려할 수 있습니다.
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.