>  기사  >  Java  >  사례 설명 JVM 메모리 공간(권장 수집)

사례 설명 JVM 메모리 공간(권장 수집)

Java后端技术全栈
Java后端技术全栈앞으로
2023-08-15 17:16:461185검색

오늘은 JVM 메모리 공간에 대한 주제로 이야기를 나눠보겠습니다. 이 역시 1위 인터넷 기업의 인터뷰에서 자주 묻는 질문이기도 합니다. 친구들이 모아서 자주 읽어보고 이해하는 것이 좋습니다. 좋아요, 더 이상 이야기하지 마세요. 오늘은 주요 주제로 들어가겠습니다.

JVM은 메모리를 여러 데이터 영역으로 나누는데, 로드된 클래스는 어디에 할당되나요?

아래 그림은 메소드 영역, 힙, 가상 머신 스택, 로컬 메소드 스택 및 프로그램 카운터를 포함한 다양한 메모리 영역을 보여줍니다.

사례 설명 JVM 메모리 공간(권장 수집)

메서드 영역

메서드 영역은 클래스 정보, 상수, 정적 변수, JIT 컴파일러로 컴파일된 코드 등 로드된 데이터를 저장하는 데 사용됩니다. 가상머신으로. 클래스 로딩의 5단계는 클래스 로딩에 언급되어 있습니다. 로딩 단계에서는 바이트 스트림으로 표현되는 정적 저장 구조가 메소드 영역의 런타임 데이터 구조로 변환됩니다. 준비 단계에서는 변수에 사용되는 모든 메모리가 메소드 영역에 할당됩니다.

프로그램 카운터

심플 코드로 와서 (1+2)*3을 계산하고

public int cal() {
    int a = 1;
    int b = 2;
    int c = 3;
    return (a + b) * c;
}

를 반환합니다. 이 코드를 가상 머신에 로드하면 다음과 같은 바이트가 됩니다. 코드를 실행하면 한 줄씩 실행됩니다.

사례 설명 JVM 메모리 공간(권장 수집)

Java는 스레드가 다시 전환된 후 원래 실행 위치가 어디에 있는지 알아야 합니다. 프로그램 카운터는 이 실행 위치를 기록하는 데 사용됩니다. 스레드 간의 카운터가 서로 영향을 미치지 않도록 하기 위해 이 메모리 영역은 스레드 전용입니다.

虚拟机栈

虚拟机栈也是线程私有的,生命周期与线程相同。每个线程都有自己的虚拟机栈,如果这个线程执行了一个方法,就会创建一个栈帧,方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。比如下面的例子,fun1调用fun2,fun2调用fun3,fun3创建Hello对象。

public void fun1() {
    fun2();
}

public void fun2() {
    fun3();
}

public void fun3() {
    Hello hello = new Hello();
}

调用的时候,流程图如下:

사례 설명 JVM 메모리 공간(권장 수집)

执行完成的时候,流程图如下:

사례 설명 JVM 메모리 공간(권장 수집)

每一个栈帧都包括了局部变量表、操作数栈、动态连接、方法返回地址和一些额外的附加信息。局部变量主要是存放方法参数以及方法内部定义的局部变量,操作数栈是一个后入先出栈,当方法刚刚开始执行的时候,这个方法的操作数栈是空的,在方法的执行过程中,会有各种字节码指令往操作数栈中写入和提取内容,也就是出栈/入栈操作。

我们通过上面(1+2)*3的例子,把方法区、程序计数器、虚拟机栈的协同工作理一下。首先通过javap查看它的字节码,经过类加载器加载后,此时这个字节码存在方法区中。stack表示栈深度是2,locals是本地变量的slot个数,args_size是入参的个数,默认是this。栈的深度、本地变量个数,入参个数,都是在编译器决定的。

사례 설명 JVM 메모리 공간(권장 수집)

如下图,指令的位置是方法区,局部变量和操作数栈的位置是虚拟机栈,程序计数器就在程序计数器(这个下面的图就不再重复)。当执行偏地址为0的指令的时候,程序计数器为0,局部变量第一个值是this,当前的指令就是方法区0:iconst_1,指令iconst_1就是把int常量值1进栈,这个1就到了虚拟机栈的操作数栈中。

사례 설명 JVM 메모리 공간(권장 수집)

当执行偏地址为1的指令的时候,程序计数器为1,把操作数栈的值赋值到局部变量,此时操作数栈清空了,局部变量多了一个1,这条指令执行完,就是对应上面int a=1的语句。

사례 설명 JVM 메모리 공간(권장 수집)

또한 두 명령문 b와 c의 할당은 명령 2, 3, 4, 5에 해당하므로 여기서는 반복하지 않겠습니다. 5를 실행한 후 아래 그림과 같이

사례 설명 JVM 메모리 공간(권장 수집)

6을 실행하면 iload_1이 실행되는데, 이는 두 번째 int형 지역 변수를 스택의 맨 위에 푸시하는 것입니다.

사례 설명 JVM 메모리 공간(권장 수집)

7을 실행하면 iload_2가 실행되는데, 이는 세 번째 int형 지역 변수를 스택 맨 위에 푸시한다는 의미입니다.

사례 설명 JVM 메모리 공간(권장 수집)

8을 실행하면 iadd 문입니다. 즉, 스택 상단에 있는 두 개의 int 유형 요소가 스택에서 튀어나오고 결과가 나온 후 스택 상단으로 푸시됩니다. 획득.

사례 설명 JVM 메모리 공간(권장 수집)

9를 실행할 때 스택 맨 위에 있는 요소 3을 다섯 번째 지역 변수에 할당합니다.

사례 설명 JVM 메모리 공간(권장 수집)

실행이 11에 도달하면 다섯 번째 지역 변수의 값이 스택의 맨 위로 푸시됩니다. 실행이 13에 도달하면 네 번째 지역 변수의 값이 실행에 도달하면 스택의 맨 위로 푸시됩니다. 14에서는 스택 상단에 있는 두 값이 스택에서 푸시되고, 곱해진 결과가 스택에 푸시됩니다. 15를 실행하면 현재 스택의 상단에 있는 int 유형 요소가 푸시됩니다. 스택은 현재 메서드에서 반환됩니다. 위의 내용과 거의 동일하므로 자세한 내용은 다루지 않겠습니다.

Heap

힙 메모리 영역의 유일한 목적은 객체 인스턴스를 저장하는 것이며 거의 모든 객체 인스턴스가 여기에 메모리를 할당합니다. 예를 들어 위의 fun1은 fun2를 호출하고 fun2는 fun3을 호출하며 fun3은 Hello 객체를 생성합니다. fun3 메소드에서 객체가 생성되면 힙에 생성되고 주소는 fun3의 지역 변수에 할당됩니다. Java 힙은 다음과 같이 세분화될 수도 있습니다. 신세대와 구세대; 신세대도 Eden 공간, From Survivor 공간 및 To Survivor 공간으로 세분화됩니다.

사례 설명 JVM 메모리 공간(권장 수집)

요약

전체 과정은 다음과 같습니다. 먼저 Java 파일을 클래스 파일로 컴파일한 후 클래스 로더를 통해 메소드 영역에 로드합니다. 스레드가 메소드를 호출하면 스택 프레임을 생성하고 메소드 영역에서 바이트코드를 읽고 명령어를 실행합니다. 명령어가 실행되면 실행 위치가 프로그램 카운터에 기록됩니다. 메소드가 실행된 후 스택 프레임이 팝됩니다.

사례 설명 JVM 메모리 공간(권장 수집)

관련 매개변수

-XX: PermSize: 영구 생성 메모리 용량.

-XX:MaxPermSize: 영구 세대의 최대 메모리 용량입니다.

-XX:MetaspaceSize: 메타스페이스의 초기값 크기

-XX:MaxMetaspaceSize: 메타스페이스의 최대 크기

-XX:CompressedClassSpaceSize: 메타스페이스에 Klass 클래스 메타데이터 부분을 저장하는 공간 크기

-Xss: 스택 메모리 용량.

-Xms: 힙 메모리 용량.

-Xmx: 런타임 확장의 영향을 방지하기 위한 힙의 최대 메모리 용량은 일반적으로 -Xms 설정과 동일합니다.

-Xmn: 신세대 메모리 용량, Old 세대는 힙 메모리 용량 - 신세대 메모리 용량

-XX: SurvivorRatio=8: 신세대도 Eden 공간, From Survivor 공간, To Survivor 공간으로 세분화됩니다. , 8로 설정 Eden 공간을 나타냅니다: From Survivor 공간: To Survivor 공간 = 8:1:1 예를 들어 새로운 세대가 10M이면 Eden 공간은 8M을 차지하고 From Survivor 공간과 To Survivor 공간은 각각 1M을 차지합니다.

사례 설명 JVM 메모리 공간(권장 수집)

위 내용은 사례 설명 JVM 메모리 공간(권장 수집)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 Java后端技术全栈에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제