가장 간단한 JVM 메모리 구조 다이어그램

JVM 메모리 구조 다이어그램


image.png

안녕하세요 여러분. 며칠 동안 업데이트하지 않았습니다. 오늘의 내용은 너무 많습니다. JVM의 내부 구조도를 자세히 소개하겠습니다. 이전과 동일합니다. 첫 번째 사례로 모든 사람이 이해할 수 있도록 생각해 내다.

/ ** 
 * @author : jiaolian 
 * @date : 작성일 : 2021-03-10 21:28 
 * @description : helloworld test jvm 메모리 영역 
 * @modified 작성자 : 
 * 공식 계정 : Calling 
 * / 
public class HelloWorldTest { 

    public static void main (String [] args) { 
        // Create a new HelloWorldTest object; 
        HelloWorldTest helloWorldTest = new HelloWorldTest (); 
        // sayHello 
        for (int i = 0; i <2; i ++) { 
            new Thread ( ()-> helloWorldTest.sayHello ( "world")). start (); 
        } 
    } 

    / ** 
     * 인사하기 
     * @param who 
     * / 
    public void sayHello (String who) {
        System.out.println (Thread.currentThread (). getName () + "hello!"+ who); 
    } 
}

위의 코드 : 메인 스레드의 for 루프에 두 개의 새 스레드를 만들어 sayHello를 호출하고 마지막 두 스레드는 각각 hello to the world! 이 코드는 이해하기 쉽기 때문에 출력 결과가 게시되지 않습니다. 우리는이 코드를 작성하고 실행했으며 주로이 코드가 JVM에서 어떻게 작동하는지 살펴 봅니다.

먼저 javac 컴파일 후 바이트 코드 HelloWorldTest.class 로 변환 될 HelloWorldTest.Java 파일을 작성하는데 왜 바이트 코드로 변환해야 하는가? Java 가상 머신이 인식 할 수 있기 때문입니다! 마지막으로, 바이트 코드는 클래스 로딩 서브 시스템 인 ClassLoader에 의해 메모리로로드됩니다. 각 메모리 블록에는 고유 한 역할이 있으며 마지막으로 실행 엔진이 바이트 코드를 실행합니다. 아래에서는 각 메모리 블록이 수행하는 역할에 중점을 둡니다!

image.png


방법 영역


메서드 영역은 주로 클래스 메타 데이터, 상수 풀, 메서드 정보, 클래스 변수 등과 같은 일부 정적 정보를 포함합니다. 위의 코드 HelloWorldTest.class는 클래스 메타 데이터이고, sayHello, main은 메소드 정보 등이 메소드 영역에 저장됩니다. 방법 영역에서 주목해야 할 두 가지 사항이 있습니다.

  1. 메서드 영역이 너무 크고 설정을 초과하면 OutOfMemoryError : PermGen 공간 오류가보고됩니다. gclib 도구는 오류를 테스트하는 클래스를 동적으로 생성 할 수 있습니다.
  2. JDK1.7 이전에는 메서드 영역을 영구 생성 이라고 했으며 1.8 이후에는 메타 스페이스 라고 했습니다 . 그 이유는 관리 압력을 해제하기 위해 JDK1.8이 런타임 상수 풀을 관리를 위해 힙에 넘겨주기 때문입니다.


더미


힙은 주로 인스턴스 객체를 저장합니다. new 키워드가 있는 객체 를 보는 이러한 방식으로 이해할 수 있으며 데이터는 힙에 저장됩니다. . 위의 코드 HelloWorldTest helloWorldTest = 새로운 HelloWorldTest ()이다 helloWorldTest 새로운 HelloWorldTest 객체 인스턴스를 가리키는 HelloWorldTest 객체에 대한 참조 인 helloWorldTest 기준은 또한 호출 스택 상에 배치되는 로컬 변수 ( 개체 유형 선언 메소드 또는 일반 유형), 다음 힙, 스택 및 메소드 영역 간의 관계 를 보여주기 위해 그림을 그립니다 . JVM이 HelloWorldTest를 실행할 때 helloWorldTest = new HelloWorldTest ();이 문장에서 JVM 메모리 구조는 다음과 같습니다. 개체에 대한 참조가 사라지면 개체는 GC에 의해 재활용됩니다.

image.png

힙 메모리에서 메모리는 젊은 세대구세대의 두 영역으로 나눌 필요가 있습니다 . 아래 그림과 같이.

  1. 신생대 : 힙 메모리에서 신생대는 세 부분으로 나뉩니다. 에덴 (에덴은 새로운 개체에 해당하는 새로운 생명을 만듭니다)에서,이 세 메모리 영역은 신생대에 속하며 기본 비율은 8 : 1입니다. : 1, 각각의 새 객체는 먼저 eden에 저장되며, eden 영역 메모리가 가득 차면 모니터 gc가 영역을 회수하도록 트리거하고 회수되지 않은 객체는 from 또는 to, from, 하나는 비어 있고 편리한 메모리로 객체가 정렬되고 메모리에 표시됩니다. 객체가 수집되고 이동 될 때마다 회수되지 않은 객체의 나이도 1 씩 증가합니다. 나이 ( 기본값은 15 세 ), 나이를 입력합니다.
  2. 나이 :. 시스템이 너무 큰 경우, 나이가 가득 차면, 전체 GC 복구이 발생됩니다, 전체 GC는 복구 할 수 없습니다 프로그램과 유사한 표시됩니다. java.lang.OutOfMemoryError와 :. Java 힙 공간을 우리는 JVM 매개 변수를 구성 할 수 있습니다. -Xmx32m 과 같은 최대 힙 메모리를 32M으로 설정합니다.

힙을 분할하는 이유는 JVM이 가비지 콜렉션자동으로 처리 하도록하기 위함입니다 . 힙 메모리는 GC에서 수집하는 주요 영역 입니다.

image.png



스택


스택 메모리 공간은 힙 공간에 비해 상대적으로 작으며 스레드 전용입니다. 메서드. 메서드에는 로컬 변수, 메서드 매개 변수 및 메서드가 포함됩니다. 내보내기, 상수 포인터 및 예외 정보 테이블에 액세스합니다. 예외 정보 테이블 및 상수 포인터 정보는 메서드 본문에 표시되지 않을 수 있지만 디 컴파일 된 Jclasslib 도구 클래스 를 통해 클래스 파일 을 생성하고 예외 정보 테이블을 처리 할 수 ​​있습니다. 프로그램이 오류를 실행하면 실행할 특정 코드 라인으로 점프하고 JVM은 예외 테이블을 통해 피드백됩니다. 우리는 여전히 예제와 다이어그램을 결합하여 자세히 분석합니다. 프로그램이 실행 중일 때 JVM의 스택이 다음 그림과 같이 나타날 수 있습니다.

image.png    

스레드는 여러 스택 프레임에 해당 할 수 있습니다. 스택 프레임은 다음 그림과 같이 맨 위에서 맨 아래로, 선입 선출푸시됩니다. 다음 그림과 같이 메서드 A에서 메서드 B를 호출하고 메서드 B에서 C를 호출하고 메서드에서 메서드를 호출합니다. C D, 메인 스레드는 스택 프레임의 스태킹 상황에 해당하고 스태킹 순서는 D-> C- > B- > A이며 최종 프로그램이 종료됩니다. 또한 피연산자 스택은 로컬 변수 계산의 중간 결과를 저장하는 것을 의미합니다. 예를 들어 int x = 1은 메소드 A에서 정의되고 로컬 변수는 JVM에서 후속 계산을 위해 피연산자 스택에 배치됩니다. 스택에도 공간 크기가 있습니다. 스택이 너무 크고 스택 깊이를 초과하는 경우 유사한 오류 ( java.lang.OutOfMemoryError : Java 스택 공간) 가보고 됩니다. 가장 일반적인 예는 재귀입니다. 데모 테스트 재귀 예제를 작성 하시겠습니까?


image.png


프로그램 카운터


프로그램 카운터는 스레드 전용입니다. 프로그램의 다중 스레드 실행은 CPU 할당 시간 조각 실행 에 따라 다릅니다 . 간단한 다이어그램을 그려 다중 스레드가 CPU 시간 조각을 사용하는 방법을 확인합니다. 아래 그림과 같이 스레드 0과 스레드 1은 CPU 타임 슬라이스를 할당하여 프로그램을 번갈아 실행합니다. 스레드 0이 먼저 타임 슬라이스를 획득한다고 가정하면 CPU는 타임 슬라이스가 소진 된 후 다시 스레드 1에 타임 슬라이스를 할당합니다. 스레드 1이 실행 된 후 이것은 타임 슬라이스가 스레드 0으로 돌아가서 실행될 때, 질문은 스레드 0이 마지막으로 어디에서 실행 되었습니까? 몇 줄의 코드가 있고 그 줄의 코드가 실행 되었습니까? 이때 프로그램 카운터가 작동하고 프로그램 카운터 스레드 실행 장면을 저장 하여 다음 작업 재개를 용이하게합니다. 이것이 프로그램 카운터 가 스레드 전용 인 이유 입니다.

image.png



네이티브 메서드 스택


네이티브 메서드 스택은 많이 도입되지 않을 것이며 스택 구조와 같이 독립적 인 영역이지만 네이티브 메서드에 해당합니다.


직접 기억


직접 메모리는 JVM 메모리 이외의 메모리와는 독립적이며 NIO 인터페이스와 직접 상호 작용할 수 있습니다. NIO 인터페이스는 자주 메모리를 작동합니다. JVM 관리에 배치하면 의심 할 여지없이 JVM 오버 헤드가 증가하므로이 부분은 별도로 제안됩니다. 데이터는 메모리에 의해 직접 조작되며 JVM에 비해 더 빠르고 프로그램의 성능을 분명히 향상시킵니다.



메모리 할당 성능 최적화 탈출 분석


그 전에 new 키워드가 보이면 객체는 힙에 할당되어야한다고 말 했으니 사례를 살펴 보자.

/ ** 
 * @author : jiaolian 
 * @date : 작성일 : 2021-03-10 16:10 
 * @description : 탈출 분석 테스트 
 * @modified By : 
 * 공개 번호 : 叫 练
 * / 
public class EscapeTest { 

    // private static Object object; 
    public static void alloc () { 
        // 객체는 이스케이프 객체가 아니라 크기가 16k와 같습니다. 
        // object = new Object (); 
        Object object = new Object (); 
    } 

    public static void main (String [ ] args) throws InterruptedException { 
        // Million times memory 
        long begin = System.currentTimeMillis (); 
        for (int i = 0; i <10000000; i ++) { 
            alloc (); 
        } 
        long end = System.currentTimeMillis ();
        System.out.println ( "시간 :"+ (끝-시작)); 
    } 
}

위의 코드에서와 같이 main 함수의 new Object에 for loop를 1 억번 사용합니다. 객체는 16k입니다. 대략 GB 데이터가있는 것으로 추정됩니다. 이때 수동으로 JVM 매개 변수 -XX를 구성합니다. : + PrintGC -Xmx10M -XX : + DoEscapeAnalysis; GC 정보를 인쇄하도록 설정하면 기본 최대 힙 메모리는 10M입니다.

  1. -XX : + PrintGC . 콘솔이 GC 정보를 인쇄 함을 나타냅니다.
  2. -Xmx10M . 최대 힙 메모리를 10M으로 설정하십시오.
  3. -XX : + DoEscapeAnalysis . 이스케이프 분석을 활성화 합니다 ( 기본적으로 활성화).

프로그램을 실행하면 인쇄 결과가 아래 그림과 같습니다. 총 3 개의 GC 수행되었습니다. 질문이 있으 십니까? 10M 힙 메모리는 GB 데이터 영향을 수용해야합니다. 왜 N 개의 GC가 필요한데 왜 3 개의 GC 만 필요합니까? -XX 경우 : - DoEscapeAnalysis 가까운 탈출 분석, GC는 수천 번 발생할 수 있습니다. 실행 시간도 3 밀리 초에서 1000 밀리 초 이상으로 늘어났습니다. 이스케이프가 아닌 객체가 새로 빌드 된 힙에 빌드되지 않고 스택에 빌드되었음을 보여줍니다 . 이를 통해 얻을 수있는 이점 : 프로그램 GC의 실행 횟수 및 실행 시간의 관점에서 프로그램 작업의 효율성이 향상됩니다.

image.png

  • 원인 분석 :

위의 경우 코드에서 alloc () 메서드를 관찰하십시오. Object object = 메서드에서 new Object (), object는 지역 변수입니다. 새로 생성 할 때마다 다음주기에 생성됩니다. 마지막으로 생성 된 객체가 팝됩니다. 뾰족한 개체는 무효화되고 유효하지 않은 개체는 GC에 의해 회수됩니다. 이스케이프 분석이 켜지면 new Object ()에 의해 생성 된 객체는 힙에 할당되지 않고 스택에 배치됩니다. 이것이 JVM이 이스케이프 분석을 통해 메모리를 최적화하는 방법입니다. 그것에 대해 생각해 보면, 당신이 private static Object 객체를 놓아 주면, 주석, 객체는 여전히 비 이스케이프 객체일까요?

참고 : 이스케이프 개체는 스택에 공간을 할당 할 수 없습니다!

지금 쯤이면 탈출 분석에 대해 더 명확하게 이해해야 한다고 생각합니다 .


요약하자면


좋아요, 글쓰기가 좀 지겨워 요. 아직 미완성이고 수정해야 할 부분이 많이 남아 있습니다. 수정하고 댓글을 달 수 있기를 바랍니다. 마음에 들면 좋아요를 누르고 주목 해주세요. 주의 포인트, 길을 잃지 마세요, 나는 [ 연습이라고 ] 공개 번호 , 마이크로 신호 [jiaolian123abc] 가 연습하면서 그들에게 말하고있었습니다.

image.png


추천

출처blog.51cto.com/14883474/2656420