JVM의 기본 원리 배우기 (3) JVM 메모리 영역

이전 기사에서는 주로 클래스 로딩 서브 시스템에 대해 배웠고,이 기사에서는 JVM의 런타임 데이터 영역을 배웠습니다.

이전 : JVM (2 개) 로딩 하위 시스템의 기본 원칙 배우기

런타임 데이터 영역

계획의 다른 영역에 저장된 다양한 유형의 컨텐츠의 JVM 디자이너 JVM 이러한 영역은 아래 의 런타임 데이터 영역 ( 런타임 데이터 영역)을 요약 합니다.

The Java Virtual Machine defines various run-time
data areas that are used during execution of a
program. Some of these data areas are created on
Java Virtual Machine start-up and are destroyed only
when the Java Virtual Machine exits. Other data
areas are per thread. Per-thread data areas are
created when a thread is created and destroyed when
the thread exits.
译:
Java虚拟机定义了在程序执行期间使用的各种运行时数据区域。
其中一些数据区域是在Java虚拟机启动时创建的,只有在Java虚拟机
退出时才会被销毁。有的数据区域是线程独享的,数据区域在创建线程
时创建,在线程退出时销毁。

런타임 데이터 영역
여기에 사진 설명 삽입

방법 영역

  • 메소드 영역은 가상 머신이 시작될 때 생성되는 각 스레드가 공유하는 메모리 영역입니다.
  • 저장되는 것은 자주 변경되지 않는 데이터 내용이며 기본적으로 빈번한 GC가 발생하지 않습니다.
  • Java 가상 머신 스펙은 메소드 영역을 힙의 논리적 부분 으로 설명하지만 Java 힙과 구별하기 위해 Non-Heap (비힙)이라는 별칭이 있습니다. 따라서 힙 영역은 별도로 수집됩니다.
  • 가상 머신에서로드 한 클래스 정보 , 상수 , 정적 변수 (JDK1.6), Just-In-Time 컴파일러에 의해 컴파일 된 코드 등 을 저장하는 데 사용됩니다 .
    • 유형 정보 (클래스 메타 정보) : (클래스 클래스, 인터페이스 인터페이스, 열거 형 열거 형, 주석)
      • 이 클래스의 유효한 전체 이름 (전체 이름 = 패키지 이름. 클래스 이름)
      • 이 유형의 직계 상위의 완전하고 유효한 이름입니다. 인터페이스 또는 객체에 대한 상위가 없습니다.
      • 이 유형의 수정 자, public, abstract, final —> 2를 N의 거듭 제곱으로 표현
    • 필드 정보 (도메인 정보)
      • JVM은 필드의 선언 순서뿐만 아니라 메소드 영역에 유형 정의의 모든 관련 정보를 저장해야합니다.
      • 도메인 관련 정보에는 도메인 이름, 도메인 유형, 도메인 수정자가 포함됩니다.
    • 방법 정보
      • 이 메서드의 메서드 이름
      • 메서드의 수정 특성은 공개, 추상, 최종 —> 2의 N 제곱을 나타냅니다.
      • 메서드의 반환 유형 (void 포함)
      • 방법 매개 변수 목록 (유형 + 번호)
      • 바이트 코드 명령어 (바이트 코드), 피연산자 스택, 지역 변수 테이블의 방법
    • 런타임 상수 풀
      바이트 코드 파일에는 상수 풀이 포함되어 있으며, 바이트 코드 파일의 상수 풀을 런타임 상수 풀인 런타임시 메소드 영역으로로드합니다.
      • 문자열 테이블 문자열 상수 풀은 JDK1.6 버전의 메서드 영역에 저장되며 JDK1.7에서는 JDK1.8이 힙으로 이동했습니다.
    • 정적 변수 (비 정적 변수)
      JDK1.6 버전, 정적 변수는 메소드 영역에 저장됩니다 .JDK1.7에서는 JDK1.8이 힙으로 이동했습니다.
    • JIT Just-In-Time 컴파일 된 코드
  • 메서드 영역이 메모리 할당 요구 사항을 충족 할 수없는 경우 OutOfMemoryError 예외가 발생합니다.
  • 메소드 영역은 정의 (표준)이고 다른 버전의 구현이 다릅니다
    .1.7 이전 메소드 영역 구현을 Perm 공간 (JVM 직접 제어)
    이라고합니다. 1.8 이후에는 메타 공간 (운영 체제의 직접 메모리)이라고합니다. JVM은 직접 모니터링 및 제어 할 수 없습니다.)
  • 메소드 영역은 JVM이 시작될 때 생성되고 모든 스레드에서 공유되며 해당 수명주기는 JVM 가상 머신과 일치합니다.

JDK1.6 버전 메소드 영역 스토리지 세부 사항 :

여기에 사진 설명 삽입

JDK1.7 버전 메소드 영역 스토리지 세부 사항

여기에 사진 설명 삽입

JDK1.8 버전 메소드 영역 스토리지 세부 사항 :

여기에 사진 설명 삽입

런타임 상수 풀

Each run-time constant pool is allocated from the Java Virtual Machine's method area
译:
运行时常量池是分配至方法区的. 即 运行时常量池属于方法区的一部分.(jdk1.6之前属于方法区,1.7之后属于堆区)

즉, 바이트 코드 파일의 상수는 런타임에 런타임 상수 풀에로드됩니다.

더미

  • 힙은 JVM (Java Virtual Machine)에서 관리하는 가장 큰 공유 메모리 조각으로, 가상 머신이 시작될 때 생성되고 모든 스레드에서 공유됩니다.
  • ** "거의"** 모든 Java 개체 인스턴스 및 배열이 힙에 할당됩니다.
  • 힙은 가비지 콜렉션을 수행하는 GC의 초점입니다.
    힙 공간 다이어그램 :
    여기에 사진 설명 삽입
  • 메서드 영역과 힙의 두 부분으로 나뉘는 이유는 무엇입니까?

메소드 영역은 자주 변경되지 않는 데이터 콘텐츠를 저장합니다. 빈번한 GC
작업은 기본적으로 발생하지 않습니다 . 예를 들어 클래스 정보, 메소드 정보, 필드 정보, jit 컴파일 된 코드,
힙은 런타임에 생성 된 데이터 객체를 저장합니다. 이러한 콘텐츠는 자주 사용됩니다. 기억에 남다

  • 힙이 Old와 Young의 두 부분으로 나뉘는 이유는 무엇입니까?

힙은 JAVA 실행 프로세스에서 가장 중요한 공유 작업 메모리입니다. JVM 메커니즘은 공유 메모리 쓰레기를 자동으로 관리하는 가상 머신입니다 ... 객체를 수집 할 때마다 전체 힙 영역을 스캔하면 많은 작업 및 성능 손실.

  • 젊은이를 에덴, S0, S1의 세 영역으로 구분해야하는 이유는 무엇입니까?

영지의 메모리 사용량이 일정량에 도달하면 이때 직접 정리하면 공간 분할 문제가 발생합니다. 또한 영지의 사물은 일반적으로 생사입니다. 따라서 대부분의 콘텐츠가 정리됩니다. 남아있는 개체는 s0 또는 s1에 배치되어 가비지 수집 및 정리에 도움이됩니다.

  • 신세대에서 Eden : S0 : S1의 비율이 기본적으로 8 : 1 : 1 인 이유는 무엇입니까?

IBM의 특별 연구에 따르면 차세대 개체의 약 98 %가 "살아있다가 죽는다"고합니다. 8 : 1 : 1은 많은 실험과 데이터 수집 및 분석을 기반으로 한 합리적인 비율입니다.

메모리 예외

  • 힙 비정상 OutOfMemoryError
    는 프로그램 작동 매개 변수를 조정합니다. -Xmx20M -Xms20M
  • 메서드 영역 비정상 OutOfMemoryError
    매개 변수 조정 -XX : MetaspaceSize = 30M -XX : MaxMetaspaceSize = 30M

자바 객체의 레이아웃

힙에 저장된 내용은 Java 객체이므로 공유 메모리에 객체가 배치되는 방식을 살펴 보겠습니다.

여기에 사진 설명 삽입
Java 객체는 공유 메모리에 객체 헤더, 인스턴스 데이터 및 정렬 패딩의 세 부분을 포함합니다.
배열 객체 인 경우 객체 헤더에 배열 길이의 추가 길이가 있습니다.

개체 헤더
  • markoop (markword) 8 바이트
  • klassOop (클래스 포인터) 압축 된 포인터가 활성화 된 경우 8 바이트 (4 바이트)
  • 길이 4 바이트
개체 실제 데이터
  • 부울 및 바이트 1 바이트
  • 짧고 문자 2 바이트
  • int 및 float 4 바이트
  • long 및 double 8 바이트
  • 참조 8 바이트
패딩 정렬 (존재할 수 있음)

객체의 크기가 8 바이트의 정수배인지 확인
여기에 사진 설명 삽입
합니다. Java 객체의 수명.
정상적인 상황에서 새로 생성 된 객체는 Eden 영역에 할당되고 일부 특수 대형 객체는 Old 영역에 직접 할당됩니다.

我是一个普通的java对象,我出生在Eden区,在Eden区我还看到和我长的很像的小兄弟,我们在Eden
区中玩了挺长时间。有一天Eden区中的人实在是太多了,我就被迫去了Survivor区的“From”区,自从
去了Survivor区,我就开始漂了,有时候在Survivor的“From”区,有时候在Survivor的“To”区,居无定
所。直到我15岁的时候,爸爸说我成人了,该去社会上闯闯了。于是我就去了年老代那边,年老代
里,人很多,并且年龄都挺大的,我在这里也认识了很多人。在年老代里,我生活了20年(每次GC加
一岁),然后被回收。

출생부터 회복까지 피험자의 순서도 :
여기에 사진 설명 삽입

Java 객체가 정말 이런가요?
스택에 할당
  • 스택에 할당해야하는 이유
    JAVA 프로그램을 실행하는 과정에서 실제로 메서드로 이스케이프되지 않는 개체 범위의 참조 유형이 많이 있습니다. 즉, 개체의 수명주기가 메서드와 일치합니다. . 이러한 유형의 객체의 경우 객체가 힙 공간에 할당되지 않았 음을 고려해야합니까? 그렇다면
    스레드가 종료 된 후 객체가 힙 공간에서 가비지가되어 GC 성능이 소모됩니다.
    따라서, 메소드를 벗어나지 않는 객체를 겨냥한 JVM 객체의 속성 (집 계량)을 분산하여 스택 (스택 메모리에 속하는 스레드 전용)에 할당 할 수있는 방법입니다.
    스택 에있는 객체 이스케이프합니다.
    여기에 사진 설명 삽입

  • 스택 할당 활성화 방법
    -XX : + DoEscapeAnalysis
    -server

  • 물체 탈출 분석의 장점 켜기

    • 젠록 제거
      여기에 사진 설명 삽입

    • 스칼라 교체
      스칼라 교체 : 더 이상 분해 할 수없는 수량입니다.
      (8 가지 기본 유형 byte, short, int, long, char, float, double
      , boolean) 또한 객체에 대한 참조도 스칼라입니다. 집계는
      계속해서 분해 될 수 있는 양 입니다. 예를 들어 객체가 여러 스칼라로 분해 될 수 있습니다.
      Java 객체를 디스 어셈블하고 해당 멤버 변수를 분산 된 변수로 복원하는 경우이를 스칼라 대체라고합니다. 분해 된 변수는 개별적으로 분석 및 최적화 할 수 있으며 활동 기록 (스택 프레임 또는 레지스터)에 개별적으로 공간을 할당 할 수 있습니다. 원래 객체는 전체 공간을 할당 할 필요가 없습니다.

JVM
-XX:+EliminateAllocations	可以开启标量替换
-XX:+PrintEliminateAllocations	查看标量替换情况
TLAB (스레드 로컬 할당 블록)

이전 내용에서 일반적인 시나리오에서는 힙영 에덴에 객체가 할당되어 있고 힙은 전역 적으로 공유되는 영역이라는 것을 알고 있습니다. 여러 스레드가 힙 메모리를 작동하여 동시에 객체 공간을 할당 할 때 동기화 또는 문자열은 필수. 행 작업. 반드시 동일한 공간 경합의 동시성 문제를 일으키는 것은 아닙니다. 동기화 (직렬)를 사용하여 개체 할당을 가져 오면 할당 효율성이 확실히 저하됩니다 (JVM은 할당 실패를 처리하기 위해 CAS를 사용하지만).

TLAB는이 문제를 해결하기위한 설계입니다 .Eden 영역에서는 쓰레드가 시작되면 각 쓰레드 전용의 작은 버퍼 공간이 열린다. 이후 쓰레드는 TLAB 공간을 내려 놓을 수있는 한 객체를 생성해야한다. 개체 할당의 효율성을 높이기 위해 동기화 (문자열 OK)를 피하십시오.

-XX : + UseTLAB
-XX : TLABSize = 512K

개체 할당 프로세스

여기에 사진 설명 삽입
인터뷰 질문들

  • 힙에 쌓기
public static void main(String[] args){ 
	Object obj = new Object();
}
  • 메소드 영역이 힙을 가리킴
public static Object obj = new Object();	// JDK1.6版本
  • 힙은 메소드 영역을
    가리 킵니다. 객체 레이아웃의 마크 워드에 클래스 포인트가 있습니다.

  • 스택 오브젝트의 경량 잠금을 가리키고 오브젝트 헤더 정보는 스택 공간의 잠금 레코드를 가리 킵니다.

Java Virtual Machine 스택 (가상 머신 스택)

  • 가상 머신 스택은 현재 실행 스레드의 배타적 공간으로 스택 데이터 구조의 형태로 존재합니다.
  • 가상 머신 스택은 스레드가 실행되는 영역이며 스레드에 메서드의 호출 상태를 저장합니다. 즉, Java 스레드의 실행 상태는 현재 스레드에 연결된 가상 머신 스택에 의해 저장됩니다.
  • 스레드에 의해 실행되는 각 메서드는 스택의 스택 프레임입니다. 즉, 각 메서드는 스택 프레임에 해당합니다 . 메서드가 호출되면 스택 프레임이 스택으로 푸시되고 메서드가 호출되면 스택 프레임이 스택에서 팝됩니다.

스택 프레임

스택 프레임의 수명주기는 메서드 호출과 관련이 있습니다. 각 스택 프레임은 메서드의 실행 공간으로 이해 될 수있는 호출 된 메서드에 해당합니다.

  • 스택 프레임은 메소드가 호출 될 때 생성되고 메소드가 종료되면 소멸됩니다. 끝은 정상 종료 또는 비정상 종료입니다.
    스택 프레임의 개략도 :
    여기에 사진 설명 삽입
  • 메서드 반환 주소 (일반 메서드 호출 완료 및 Abrupt 메서드 호출 완료) : 메서드 반환 주소 : 메서드가 실행되기 시작할 때 종료하는 방법은 두 가지뿐입니다. 하나는 메서드에서 반환 된 바이트 코드 명령을 만나는 것입니다. 예외를 충족하고이 예외는 메서드 본문에서 처리되지 않습니다. 또는 메소드 실행 후 종료로 이해
  • 런타임시 동적 연결 (동적 연결) : 각 스택 프레임에는 런타임 상수 풀에서 스택 프레임이 속한 메서드에 대한 참조가 포함됩니다.이 참조는 메서드 호출 중 동적 연결을 지원하기 위해 유지됩니다.
    클래스에서 그것들은 모두 심볼릭 참조입니다 ... method_ref는 동일하지만 실행 또는 호출 단계에서 메소드의 특정 실행 버전을 알아야합니다. 따라서 동적 연결은 특정 메소드 영역을 가리키는 메소드 참조입니다. 메서드 확인은 실행 단계에 있어야합니다. 지정 만 가능하므로 동적 링크라고합니다.
  • 로컬 변수 테이블 (Local Variables) : 이 테이블에서 직접 사용하지 않는 변수의 로컬 변수 테이블을 저장 하는 방법매개 변수에 정의 된 로컬 변수는 필요에 따라 해당 명령어를 통해 피연산자에로드해야합니다 (복사 ) 스택에서 피연산자로 사용됩니다.
  • 메서드 로컬 변수 테이블에는 정적 메서드에 3 개의 로컬 변수 만 있고 인스턴스 메서드에는 4 개의 로컬 변수 가 있습니다 .

인스턴스 메서드에서 지역 변수 테이블의 아래 첨자는 1부터 시작합니다. 위치 0은 기본적으로
this 개체 이므로 정적 메서드는 그렇지 않습니다.

  • 피연산자 스택 (연산자 스택) : 스택의 데이터 구조입니다. 피연산자의 값은 스택을 푸시하고 팝하여 저장됩니다.
    지식 포인트 :
    피연산자 스택 설계 이유
    JVM의 명령 세트 아키텍처는 스택의 명령 세트 아키텍처
    가상 머신을 기반으로합니다. 명령어 세트 아키텍처 레지스터 명령어 세트 아키텍처를 기반으로하는 또 다른 명령어 세트 아키텍처가 있습니다.
    여기에 사진 설명 삽입

스택 형 명령어 세트 아키텍처 (JVM)

  • 대부분의 명령어는 주소가 0 인 명령어이며 실행 프로세스는 Java 가상 머신 스택의 피연산자 스택에 완전히 종속됩니다.
    명령어는 일반적으로 두 가지 주요 구성 요소 인 opcode와 피연산자로 구성됩니다.
    주소가 0 인 명령어에는 opcode 만 있고 피연산자는 없습니다. . 이 명령어에는 두 가지 상황이 있습니다. 하나는 피연산자가 필요하지 않다는 것이고 다른 하나는 피연산자가 기본값 (암시 적)이라는 것입니다.
  • 제로 주소 명령어이기 때문에 생성 된 명령어 공간이 덜 차지합니다.
  • 물리적 하드웨어 리소스, 강력한 이식성, 더 나은 크로스 플랫폼에 국한되지 않음

명령어 세트 아키텍처 등록 (Davlik)

  • 명령어는 1 번지 명령어, 2 번지 명령어, 3 번지 명령어를 채택하며 실행 프로세스는 하드웨어 레지스터에 따라 다릅니다.
  • 명령 공간이 더 많이 차지하지만 완료된 기능은 더 복잡 할 수 있습니다 (더 복잡한 작업을 완료하는 데 더 적은 명령이 필요함).
  • 성능이 더 좋고 실행이 더 효율적입니다.
  • 명령어 세트는 하드웨어 리소스에 따라 다르며 이식성이 제한됩니다.

케이스 (메소드 반전)

여기에 사진 설명 삽입

  • iconst_3 : int 상수 3을 피연산자 스택의 맨 위로 푸시
  • istore_0 : 피연산자 스택 맨 위에있는 int 유형의 값을 인덱스가 0 인 지역 변수 테이블의 변수에 할당합니다.
  • i_load_1 : 로컬 변수 테이블에서 인덱스 1이있는 int 유형 값을 피연산자 스택의 맨 위로 푸시
  • iadd : 피연산자 스택 맨 위에 두 개의 int 유형 값을 추가합니다.
  • i_load_2 : 로컬 변수 테이블에서 인덱스가 2 인 변수의 int 유형 값을 피연산자 스택의 맨 위로 푸시
  • ireturn : 메소드의 리턴으로 피연산자 스택 맨 위에있는 int 유형 값

스택 예외

Java의 불합리한 재귀로 인해 Java 가상 머신 스택 오버플로가 발생합니다.

public class StackOverflowDemo {
    private static int count=0;
    public static void method1(){
		count++;
		System.out.println("stack count: "+count); method1();
    }
    public static void main(String[] args) {
		method1(); }
	}

실행 후 스택의 깊이를 인쇄하고 마지막으로 stackoverflowExecption
이 -Xss256k를 통해 가상 머신 스택 공간의 크기를 조정할 수 있다고보고 할 수 있습니다.

PC 레지스터 (프로그램 카운터)

우리 모두는 프로그램의 논리적 실행이 가장 작은 실행 단위 스레드를 기반으로 실행되어야한다는 것을 알고 있습니다.

JVM 프로세스에서 실행되는 여러 스레드가 있어야하며 스레드의 내용이 실행할 권한을 가질 수 있는지 여부는 CPU 스케줄링에 따라 결정됩니다.

스레드 A가 어딘가에서 실행 중이고 갑자기 CPU의 실행 권한을 잃고 스레드 B로 전환하면 스레드 A가 다시 CPU 실행 권한을 얻었을 때 이전 상태와 논리를 유지하여 실행을 계속할 수 있습니까? 이것은 스레드에서 현재 실행 상태 기록을 유지하고, 스레드 실행 위치를 기록하여 다음에 CPU 실행 권한을 획득 할 때이 상태를 기반으로 스레드의 실행이 복원 될 수 있도록해야합니다. 등록하면됩니다.

팁 :

  • 스레드가 Java 메소드를 실행하면 카운터는 실행중인 가상 머신 바이트 코드의 명령어 주소를 기록합니다.
  • 로컬 메서드가 실행중인 경우 카운터 값은 (undefined)입니다.
  • 런타임 데이터 영역에 OOM이 나타나지 않는 유일한 영역, 가비지 수집이 없습니다.
  • 각 스레드에는 독립적 인 프로그램 카운터가 있으며 스레드는 서로 영향을주지 않습니다.

네이티브 메서드 스택

JDK 소스 코드에는 많은 Native 메소드가 있습니다. 예를 들어 hashcode ... 이러한 메소드는 모두
C / C ++ 코드로 구현 된 로직입니다.

자바의 실행 과정에서 우리는 종종 C의 네이티브 메서드를 호출하여 함수 구현을 완료합니다 .C / C ++ 코드 구현을위한 메서드 (즉, 이러한 네이티브 수정 메서드)는 프로세스를 호출합니다. method 실행 연산 로직과 연산 데이터로 로컬 메소드 스택이 바로 그 역할입니다.

실행 엔진

공식 웹 사이트 아키텍처 다이어그램
여기에 사진 설명 삽입

问:JAVA到底是解释型语言还是编译型语言?
javac是java的前置编译器,他的主要职责是将java源文件编译成class文件.
在jvm虚拟机中运行过程中,还需要将class文件解析机器能识别的机器码.所以在jvm的执行引擎中存在解释器.
所以java语言兼顾编译型和解释型的特点.

여기에 사진 설명 삽입

mixed mode ---> 指的jvm的执行class过程,存在解释执行和即时编译的即时编译器.

-Xint	-Xcomp	参数指定方式进行编译或者解释执行.

실행 엔진 아이콘
여기에 사진 설명 삽입

통역사

클래스 바이트 코드 파일을 한 줄씩 기계 코드로 변환하고 즉시 실행을 위해 CPU로 넘깁니다.

JIT 컴파일러

실행 과정에서 핫 코드가 감지되고 핫 코드가 미리 컴파일됩니다. 미리 컴파일 된 코드가 메소드 영역에 저장됩니다. 컴파일 된 기계 코드 명령은 핫 코드를 다시 실행하는 과정에서 직접 사용할 수 있습니다. 다시 해석하거나 컴파일 할 필요가 없습니다.

가비지 컬렉션

자바 언어의 인기, 즉 공유 메모리 관리에는 매우 중요한 이유가 있습니다. 공유 객체의 재활용 메커니즘 이전 C / C ++ 코드에서는 엔지니어가 공유 객체의 메모리를 관리해야했습니다. JVM 가비지 콜렉션이 장치는 객체의 생사를 자동으로 처리하도록 도와줍니다. 가비지 콜렉션 메커니즘의 대상이되는 영역 메소드는 & 힙입니다.

JVM 개요 다이어그램

여기에 사진 설명 삽입
다음 게시물 : JVM (4 개) 가비지 수집의 기본 원칙 학습

추천

출처blog.csdn.net/nonage_bread/article/details/108065454