1 개요
Java는 플랫폼 불가지론, 보안 및 네트워크 이동성을 지원하는 것으로 알려져 있습니다. Java 플랫폼은 Java Virtual Machines 및 Java Core 클래스로 구성되어 있으며, 이는 낮은 운영 체제에 관계없이 순수한 Java 프로그램을위한 통합 프로그래밍 인터페이스를 제공합니다. Java Virtual Machine이 "한 번 컴파일되고 모든 곳에서 실행"이라고 주장하는 것은 바로 Java 가상 머신 때문입니다.
1.1 Java 프로그램 실행 프로세스
Java 프로그램의 실행은 컴파일 환경과 실행 환경에 따라 다릅니다. 소스 코드는 실행 가능한 기계 코드로 변환되며 다음 프로세스에 의해 완료됩니다.
Java 기술의 핵심은 모든 Java 프로그램이 가상 머신에서 실행되기 때문에 Java Virtual Machine입니다. Java 프로그램의 운영에는 Java Virtual Machine, Java API 및 Java 클래스 파일의 협력이 필요합니다. Java Virtual Machine 인스턴스는 Java 프로그램을 실행할 책임이 있습니다. Java 프로그램이 시작되면 가상 머신 인스턴스가 탄생합니다. 프로그램이 종료되면 가상 머신 인스턴스가 죽습니다.
Java의 크로스 플랫폼 기능에는 다른 플랫폼을 대상으로하는 가상 머신이 있기 때문입니다.
1.2 Java 가상 머신
Java 가상 머신의 주요 작업은 클래스 파일을로드하고 바이트 코드를 실행하는 것입니다. 아래 그림에서 볼 수 있듯이 Java Virtual Machine에는 클래스 로더가 포함되어 있으며 프로그램 및 API의 클래스 파일을로드 할 수 있습니다. 프로그램 실행에 필요한 클래스 만 Java API에로드되며 바이트 코드는 실행 엔진에 의해 실행됩니다.
Java 가상 머신이 호스트 운영 체제의 소프트웨어에 의해 구현되면 Java 프로그램은 로컬 메소드를 호출하여 호스트와 상호 작용합니다. Java 메소드는 Java 언어로 작성되고 바이트 코드로 컴파일되며 클래스 파일에 저장됩니다. 로컬 메소드는 C/C ++/어셈블리 언어로 작성되며 프로세서 관련 기계 코드로 컴파일되어 동적 링크 라이브러리에 저장되며 형식은 각 플랫폼에 독점적입니다. 따라서 로컬 방법은 Java 프로그램을 기본 호스트 운영 체제에 연결하는 것입니다.
Java Virtual Machine은 클래스 파일이 어떻게 생성되었는지, 변조 여부를 알지 못하므로 클래스 파일에 정의 된 유형을 안전하게 사용할 수 있도록 클래스 파일 탐지기를 구현합니다. 클래스 파일 검사기는 4 개의 독립적 인 스캔을 통해 프로그램의 견고성을 보장합니다.
class 클래스 파일 모음
・ 유형 데이터의 시맨틱 점검
bytecode 확인
・ 기호 참조 검증
바이트 코드를 실행할 때 Java Virtual Machines도 다른 내장 보안 메커니즘을 수행합니다. 이들은 Java 프로그래밍 언어로 Java 프로그램의 견고성을 보장하는 특성이며 Java Virtual Machines의 특성이기도합니다.
・ 유형-안전 참조 변환
・ 구조화 된 메모리 액세스
・ 자동 쓰레기 수집
・ 배열 경계 검사
・ 빈 견적 확인
1.3 Java 가상 기계 데이터 유형
Java 가상 머신은 특정 데이터 유형을 통해 계산을 수행합니다. 데이터 유형은 아래 그림과 같이 기본 유형과 참조 유형의 두 가지 유형으로 나눌 수 있습니다.
그러나 부울은 약간 특별합니다. 컴파일러가 Java 소스 코드를 바이트 코드로 컴파일하면 int 또는 byte와 부울을 나타냅니다. Java Virtual Machines에서 False는 0으로 표시되며 True는 0이 아닌 모든 정수로 표시됩니다. Java 언어와 마찬가지로 Java 가상 머신의 기본 유형의 값 범위는 호스트 플랫폼이 무엇이든간에 모든 가상 머신에서 64 비트 2의 보완 기능을 갖춘 서명 된 정수입니다.
ReturnAddress의 경우이 기본 유형은 Java 프로그램에서 최종 절을 구현하는 데 사용됩니다. Java 프로그래머는이 유형을 사용할 수 없으며, 그 값은 가상 머신 명령어의 Opcode를 가리 킵니다.
2 아키텍처
Java Virtual Machine 사양에서 가상 머신 인스턴스의 동작은 서브 시스템, 메모리 영역, 데이터 유형 및 지침의 관점에서 설명되며 이러한 구성 요소는 함께 추상 가상 머신 내부 아키텍처를 보여줍니다.
2.1 클래스 파일
Javaclass 파일에는 클래스 또는 인터페이스에 대한 모든 정보가 포함되어 있습니다. 클래스 파일의 "기본 유형"은 다음과 같습니다.
| U1 | 1 바이트, 부호없는 유형 |
| U2 | 2 바이트, 서명되지 않은 유형 |
| U4 | 4 바이트, 서명되지 않은 유형 |
| U8 | 8 바이트, 서명되지 않은 유형 |
더 알고 싶다면 Oracle의 JVM SE7은 공식 사양을 제공합니다. Java® Virtual Machine Specification
클래스 파일의 내용 :
classfile {u4 마법; // 마술 번호 : 0xcafebabe, 그것이 Java 클래스 파일 U2 minor_version인지 여부를 결정하는 데 사용됩니다. // 마이너 버전 번호 u2 major_version; // 기본 버전 번호 U2 constant_pool_count; // 상수 수영장 크기 CP_INFO constant_pool [constant_pool_count-1]; // 상수 풀 U2 access_flags; // 클래스 및 인터페이스 레벨에서 플래그에 액세스 (| 작동을 통해 얻음) u2 this_class; // 클래스 인덱스 (상수 풀의 클래스 상수를 가리키는) U2 Super_Class; // 현재 클래스 인덱스 (상수 풀에서 클래스 상수를 가리키는) u2 interfaces_count; // 인터페이스 인덱스 카운터 U2 인터페이스 [interfaces_count]; // 인터페이스 인덱스 세트 U2 Fields_Count; // 필드 카운터 카운터 필드 _info 필드 [fields_count]; // 필드 테이블 세트 u2 method_count; // 메소드 수 카운터 메소드 _info 메소드 [Methods_count]; // 메소드 테이블 세트 u2 attributes_count; // 속성 attribute_info attributes [attributes_count]; // 속성 테이블} 2.2 클래스 로더 서브 시스템
클래스 로더 서브 시스템은 유형 정보를 찾고로드하는 일을 담당합니다. 실제로 Java Virtual Machines의 두 가지 유형의 로더가 있습니다 : 시스템 로더 및 사용자 정의 로더. 전자는 Java Virtual Machine 구현의 일부이며 후자는 Java 프로그램의 일부입니다.
bootstrapclassloader : 기본 코드로 구현 된 Java의 핵심 라이브러리를로드하는 데 사용되며 Java.lang.classloader에서 상속되지 않습니다.
・ ExtensionClassLoader : Java Extension 라이브러리를로드하는 데 사용됩니다. Java Virtual Machine의 구현은 확장 라이브러리 디렉토리를 제공합니다. 이 클래스 로더는이 디렉토리에서 Java 클래스를 찾고로드합니다.
Application Application Class Loader : Java Application (Classpath)의 클래스 경로에 따라 Java 클래스를로드합니다. 일반적으로 Java 응용 프로그램 클래스는 이로로드됩니다. ClassLoader.getSystemClassLoader ()를 통해 얻을 수 있습니다.
시스템이 제공하는 클래스 로더 외에도 개발자는 Java.lang.classloader 클래스를 상속하여 특별한 요구를 충족시켜 자체 클래스 로더를 구현할 수 있습니다.
클래스 로더 서브 시스템에는 Java Virtual Machine의 다른 여러 구성 요소와 Java.lang 라이브러리의 클래스가 포함됩니다. 클래스 로더로 정의 된 메소드는 프로그램이 클래스 로더 메커니즘에 액세스하기위한 인터페이스를 제공합니다. 또한로드 된 각 유형에 대해 Java Virtual Machine은 java.lang.class 클래스의 인스턴스를 생성하여 유형을 나타냅니다. 다른 객체와 마찬가지로, 사용자 정의 클래스 로더 및 클래스 인스턴스는 메모리의 힙 영역에 배치되며로드 된 유형 정보는 메소드 영역에 있습니다.
이진 클래스 파일을 찾아서 가져 오는 것 외에도 클래스 로더 하위 시스템은 수입 클래스의 정확성을 확인하고 클래스 변수에 대한 메모리를 할당 및 초기화하는 기호 참조를 구문 분석해야합니다. 이러한 조치는 다음 순서로 수행해야합니다.
・로드 (유형의 바이너리 데이터 찾기 및로드)
Connection (실행 검증 : 수입 유형의 정확성을 보장; 준비 : 클래스 변수에 대한 메모리를 기본값으로 초기화하고 구문 분석 : 유형의 기호 참조를 직접 참조로 변환합니다)
・ 초기화 (클래스 변수는 올바른 초기 값으로 초기화됩니다)
2.3 방법 영역
Java 가상 머신에서로드 된 유형에 대한 정보는 메소드 영역에 메모리에 저장됩니다. 가상 머신이 특정 유형을로드하면 클래스 로더를 사용하여 해당 클래스 파일을 찾은 다음 클래스 파일을 읽고 가상 머신으로 전송합니다. 그런 다음 가상 머신은 유형 정보를 추출 하고이 정보를 메소드 영역에 저장합니다. 가상 머신은 사용자 정의 클래스 로더를 통해 Java 프로그램의 동적 확장을 허용하기 때문에 방법 영역을 쓰레기 수집기에 의해 수집 할 수도 있습니다.
다음 정보는 방법 영역에 저장됩니다.
・이 유형의 완전한 자격을 갖춘 이름 (예 : 자격을 갖춘 이름 java.lang.object)
・이 유형의 직접 슈퍼 클래스의 자격있는 이름
・이 유형의 클래스 유형 또는 인터페이스 유형입니다
・이 유형의 액세스 수정 자 (공개, 초록, 최종의 하위 집합)
・ 직접 하이퍼 interface에 대한 정렬 된 자격을 갖춘 이름 목록
・이 유형의 상수 풀 (직접 상수 [스트링, 정수 및 부동 소수
・ 필드 정보 (필드 이름, 유형, 수정 자)
・ 메소드 정보 (메소드 이름, 반환 유형, 매개 변수 및 유형, 수정 자)
constant 상수를 제외한 모든 클래스 (정적) 변수
Classloader 클래스에 대한 참조 (각 유형이로드되면 가상 머신은 시작 클래스 로더 또는 사용자 정의 클래스 로더에 의해로드되는지 여부를 추적해야합니다).
Class 클래스 클래스에 대한 참조 (로드 된 각 유형에 대해 가상 머신은 Java.lang.class 클래스의 인스턴스를 작성합니다. 예를 들어 Java.lang.integer 클래스의 객체에 대한 언급이있는 경우, 손가락 객체가 참조하는 getclass () 메소드 만 호출하여 java.lang.lang.lang.lang.
2.4 힙
런타임에 Java 프로그램에서 생성 된 모든 클래스 인스턴스 또는 배열 (배열은 Java Virtual Machine의 실제 객체입니다)은 동일한 힙에 배치됩니다. Java Virtual Machine 인스턴스에는 하나의 힙 공간 만 있으므로 모든 스레드는이 힙을 공유합니다. Java Virtual Machine에는 힙에 객체를 할당하는 지침이 있지만 가상 머신이 처리를 위해이 작업을 가비지 수집기에게 전달했기 때문에 메모리를 자유롭게하는 지침이 없습니다. Java Virtual Machine Specification은 쓰레기 수집기를 시행하지 않으며 가상 머신 구현은 자체 힙 공간을 "어떤 방식 으로든"관리해야합니다. 예를 들어, 구현에는 고정 크기의 힙 공간 만 가질 수 있습니다. 공간이 채워지면 단순히 제외성 예외가 발생하여 쓰레기 물체를 재활용하는 문제를 고려하지 않지만 사양을 준수합니다.
Java Virtual Machine Specification은 힙에 Java 객체가 어떻게 표현되는지를 지정하지 않으므로 디자인 방법에 대한 가상 머신 결정을 구현합니다. 가능한 힙 디자인은 다음과 같습니다.
핸들 풀, 물체 풀. 객체의 참조는 핸들 풀에 대한 로컬 포인터입니다. 이 디자인의 이점은 힙 조각의 분류에 도움이됩니다. 객체 풀에서 객체를 움직일 때 핸들 부분은 포인터의 새 주소 만 객체를 가리키면됩니다. 단점은 객체의 인스턴스 변수에 액세스 할 때마다 두 포인터를 통해 전달되어야한다는 것입니다.
2.5 자바 스택
스레드가 시작될 때마다 Java Virtual Machine은 Java 스택을 할당합니다. Java 스택은 많은 스택 프레임으로 구성되며 하나의 스택 프레임에는 Java 메소드 호출의 상태가 포함되어 있습니다. 스레드가 Java 메소드를 호출하면 가상 머신은 새 스택 프레임을 스레드의 Java 스택으로 밀어 넣습니다. 메소드가 반환되면 스택 프레임이 Java 스택에서 팝업됩니다. Java 스택은 로컬 변수, 매개 변수, 반환 값 및 중간 작업 결과 등을 포함하여 스레드에서 Java 메소드 호출 상태를 스레드에서 저장합니다. Java 가상 머신에는 레지스터가 없으며 명령어 세트에는 Java 스택을 사용하여 중간 데이터를 저장합니다. 이 설계의 이유는 Java Virtual Machine의 명령어를 가능한 한 컴팩트하게 유지하고 일반 레지스터가 거의없는 플랫폼에서 Java Virtual Machine의 구현을 용이하게하기 때문입니다. 또한 스택 기반 아키텍처는 런타임 중에 특정 가상 머신에서 구현 한 동적 컴파일러 코드 및 인스턴트 컴파일러를 최적화하는 데 도움이됩니다.
2.5.1 스택 프레임
스택 프레임은 로컬 가변 영역, 피연산자 스택 및 프레임 데이터 영역으로 구성됩니다. 가상 머신이 Java 메소드를 호출하면 해당 클래스의 유형 정보 에서이 방법의 로컬 가변 영역과 오페라 스택 크기를 얻은 다음 이에 따라 스택 프레임 메모리를 할당 한 다음 Java 스택으로 푸시합니다.
2.5.1.1 지역 변수 영역
로컬 변수 영역은 단어 길이 단위로 0에서 계산 된 배열로 구성됩니다. 바이트 코드 명령은 0에서 시작하는 인덱스를 통해 데이터를 사용합니다. int, float, reference 및 returnAddress 유형 값은 배열에서 하나의 항목을 차지하고, 유형의 바이트, 짧은 및 char 값은 배열에 저장되기 전에 int 값으로 변환되며, 또한 하나의 항목을 차지합니다. 그러나 길고 이중 유형의 값은 배열에서 두 개의 연속 항을 차지합니다.
2.5.1.2 피연산자 스택
로컬 가변 영역과 마찬가지로 오페라 스택은 단어 길이의 배열로 구성됩니다. 표준 스택 작업 스택을 통해 액세스하고 스택을 쌓습니다. 프로그램 카운터는 프로그램 지침에 의해 직접 액세스 할 수 없으므로 Java Virtual Machine의 지침은 피연산자 스택에서 피연산자를 얻습니다. 따라서 작동은 레지스터가 아닌 스택을 기반으로합니다. 가상 머신은 대부분의 지침이 여기에서 데이터를 팝업하고 작업을 수행 한 다음 결과를 피연산자 스택으로 다시 밀어야하기 때문에 피연산자 스택을 작업 영역으로 사용합니다.
2.5.1.3 프레임 데이터 영역
로컬 가변 영역 및 피연산자 스택 외에도 Java 스택 프레임은 일정한 풀 분석, 정상 메소드 리턴 및 예외 디스패치 메커니즘을 지원하기 위해 프레임 데이터 영역이 필요합니다. 가상 머신에서 일정한 풀 데이터가 필요한 명령어를 실행하려면 프레임 데이터 영역의 상수 풀에 대한 포인터를 통해 액세스 할 수 있습니다. 상수 풀의 구문 분석 외에도 프레임 데이터 영역은 가상 머신이 Java 방법의 정상 끝 또는 비정상적인 중단을 처리하는 데 도움이됩니다. 반환이 정상적으로 종료되면 가상 머신은 통화를 시작하는 다음 명령어를 가리 키도록 프로그램 카운터를 설정하는 것을 포함하여 통화를 시작하는 메소드의 스택 프레임을 복원해야합니다. 메소드에 리턴 값이 있으면 가상 머신은 호출을 시작하는 메소드의 피연산자 스택으로 밀어야합니다. Java 메소드 실행 중 예외 종료를 처리하려면 프레임 데이터 영역은이 메소드의 예외 테이블에 대한 참조를 보유합니다.
2.6 프로그램 카운터
실행중인 Java 프로그램의 경우 각 스레드에는 프로그램 카운터가 있습니다. 프로그램 카운터를 PC 레지스터라고도합니다. 프로그램 카운터는 로컬 포인터와 ReturnAddress를 모두 보유 할 수 있습니다. 스레드가 Java 메소드를 실행하면 프로그램 카운터의 값은 항상 다음 실행 된 명령의 주소입니다. 여기의 주소는 메소드 시작 명령어에 대한 메소드 바이트 코드의 로컬 포인터 또는 오프셋 일 수 있습니다. 스레드가 로컬 메소드를 실행하는 경우 프로그램 카운터의 값은 "정의되지 않은"것입니다.
2.7 로컬 메소드 스택
모든 로컬 메소드 인터페이스는 일종의 로컬 메소드 스택을 사용합니다. 스레드가 Java 메소드를 호출하면 가상 머신은 새 스택 프레임을 생성하여 Java 스택으로 밀어 넣습니다. 로컬 메소드를 호출하면 가상 머신은 Java 스택을 변경하지 않고 더 이상 스레드 Java 스택의 새 스택으로 밀지 않습니다. 가상 머신은 단순히 동적으로 연결하고 지정된 로컬 메소드를 직접 호출합니다.
방법 영역과 힙은 가상 머신 인스턴스의 모든 스레드에서 공유됩니다. 가상 머신이 클래스 파일을로드하면 클래스 파일에 포함 된 이진 데이터의 유형 정보를 구문 분석 한 다음 유형 정보를 메소드 영역에 배치합니다. 프로그램이 실행될 때 가상 머신은 런타임시 프로그램에 의해 생성 된 모든 객체를 힙에 배치합니다.
다른 런타임 메모리 영역과 마찬가지로 로컬 메소드 스택이 차지하는 메모리 영역은 필요에 따라 동적으로 확장되거나 축소 될 수 있습니다.
3 실행 엔진
Java Virtual Machine 사양에서 실행 엔진의 동작은 명령 세트를 사용하여 정의됩니다. 실행 엔진을 구현하는 디자이너는 바이트 코드를 실행하는 방법을 결정하거나 구현을 해석하거나 즉시 컴파일하거나 칩의 명령어 또는 혼합물을 사용하여 직접 실행할 수 있습니다.
실행 엔진은 추상 사양, 구체적인 구현 또는 러닝 인스턴스로 이해할 수 있습니다. 초록 사양은 명령어 세트를 사용하여 실행 엔진의 동작을 지정합니다. 특정 구현은 소프트웨어, 하드웨어 또는 트리 기술의 조합을 포함한 다양한 기술을 사용할 수 있습니다. 런타임 인스턴스로서의 실행 엔진은 스레드입니다.
실행중인 Java 프로그램의 각 스레드는 독립적 인 가상 머신 실행 엔진의 인스턴스입니다. 스레드 수명주기의 시작부터 끝까지 바이트 코드를 실행하거나 로컬 메소드를 실행합니다.
3.1 명령 세트
이 방법의 바이트 코드 스트림은 Java 가상 시스템의 일련의 명령어로 구성됩니다. 각 명령어에는 단일 바이트 opcode와 0 개 이상의 피연산자가 포함되어 있습니다. Opcode는 수행 할 작업을 나타냅니다. 피연산자는 Java Virtual Machine에 Opcode를 실행하는 데 필요한 추가 정보를 제공합니다. 가상 기계가 명령어를 실행하면 현재 상수 풀의 항목, 현재 프레임의 로컬 변수의 값 또는 현재 프레임의 피연산자 스택 상단의 값을 사용할 수 있습니다.
추상 실행 엔진은 한 번에 하나의 바이트 코드 명령을 실행합니다. Java 가상 머신에서 실행되는 프로그램의 각 스레드 (실행 엔진 인스턴스) 가이 작업을 수행합니다. 실행 엔진은 Opcode를 얻고 Opcode에 피연산자가있는 경우 피연산자를 얻습니다. Opcode와 Follow Operand에 의해 지정된 동작을 수행 한 다음 다음 Opcode를 얻습니다. 바이트 코드를 실행하는이 프로세스는 스레드가 완료 될 때까지 계속되며, 초기 방법에서 돌아 오거나 던진 예외를 포착하지 않으면 스레드의 완료를 표시 할 수 있습니다.
4 로컬 메소드 인터페이스
JNI (JavanativeInterface)라고도하는 Java 로컬 인터페이스는 휴대 성을 위해 준비되어 있습니다. 로컬 메소드 인터페이스를 통해 로컬 메소드는 다음을 수행 할 수 있습니다.
데이터를 전달하거나 반환합니다
작동 인스턴스 변수
클래스 변수를 작동하거나 클래스 메소드를 호출합니다
피연산자 어레이
힙 물체를 잠그십시오
새로운 수업을로드하십시오
예외를 던지십시오
Java 방법을 호출하는 로컬 방법으로 던져진 예외를 포착하십시오.
가상 머신에서 던진 비동기 예외를 캡처하십시오
쓰레기 수집기 물체가 더 이상 필요하지 않음을 나타냅니다.
요약
위의 내용은 Java Virtual Machine Architecture에 대한 심층적 인 이해에 관한이 기사에 관한 것이며, 모든 사람에게 도움이되기를 바랍니다. 관심있는 친구는이 사이트의 다른 관련 주제를 계속 참조 할 수 있습니다. 단점이 있으면 메시지를 남겨 두십시오. 이 사이트를 지원해 주신 친구들에게 감사드립니다!