1. Java 가상 머신이란 무엇입니까?
1. 추상적인 Java 가상 머신 사양. 3. 실행 중인 Java 가상 머신. 가상 머신. 머신 인스턴스
2. Java 가상 머신의 수명 주기
실행 중인 Java 가상 머신에는 Java 프로그램 실행이라는 명확한 작업이 있습니다. 프로그램이 실행을 시작할 때 실행되고 프로그램이 끝나면 중지됩니다. 동일한 시스템에서 세 개의 프로그램을 실행하면 세 개의 Java 가상 시스템이 실행됩니다.
Java 가상 머신은 항상 main() 메소드로 시작합니다. 이 메소드는 공개되어야 하며 void를 반환하고 문자열 배열을 직접 허용해야 합니다. 프로그램이 실행될 때 main() 메소드를 JVM(Java Virtual Machine)으로 랩핑하는 클래스 이름을 지정해야 합니다.
Main() 메소드는 프로그램의 시작점이며, 이것이 실행되는 스레드는 프로그램의 초기 스레드로 초기화됩니다. 프로그램의 다른 모든 스레드는 그에 의해 시작됩니다. Java에는 데몬 스레드와 비데몬 스레드라는 두 가지 유형의 스레드가 있습니다. 데몬 스레드는 Java Virtual Machine 자체에서 사용하는 스레드입니다. 예를 들어 가비지 수집을 담당하는 스레드는 데몬 스레드입니다. 물론 자신의 프로그램을 데몬 스레드로 설정할 수도 있습니다. Main() 메서드를 포함하는 초기 스레드는 데몬 스레드가 아닙니다.
Java Virtual Machine에서 실행 중인 일반 스레드가 있는 한 Java Virtual Machine은 중지되지 않습니다. 충분한 권한이 있는 경우 exit() 메서드를 호출하여 프로그램을 종료할 수 있습니다.
3. Java Virtual Machine의 아키텍처
일련의 하위 시스템, 메모리 영역, 데이터 유형 및 사용 지침은 Java Virtual Machine의 사양에 정의되어 있습니다. 이러한 구성요소는 Java 가상 머신의 내부 구조를 구성하며 Java 가상 머신 구현을 위한 명확한 내부 구조를 제공할 뿐만 아니라 JVM(Java Virtual Machine) 구현의 외부 동작을 엄격하게 규제합니다.
각 Java 가상 머신에는 프로그램에서 유형(클래스 및 인터페이스)을 로드하고 고유한 이름을 부여하는 클래스 로더 하위 시스템(클래스 로더 하위 시스템)이 있습니다. 각 Java 가상 머신에는 로드된 클래스에 포함된 명령어 실행을 담당하는 실행 엔진(실행 엔진)이 있습니다.
프로그램을 실행하려면 바이트코드, 로드된 클래스의 기타 추가 정보, 프로그램 내 개체, 메서드 매개변수, 반환 값, 지역 변수, 처리된 중간 변수 등 일정량의 메모리 공간이 필요합니다. JVM(Java Virtual Machine)은 이 모든 정보를 데이터 영역에 저장합니다. 모든 JVM(Java Virtual Machine) 구현에는 데이터 영역이 포함되어 있지만 JVM(Java Virtual Machine) 사양의 데이터 영역 조항은 매우 추상적입니다. 많은 구조적 세부 사항은 Java 가상 머신 구현자에게 맡겨집니다. 다양한 Java 가상 머신 구현의 메모리 구조는 매우 다양합니다. 일부 구현에서는 많은 메모리를 사용할 수 있지만 일부 구현에서는 가상 메모리를 사용할 수도 있고 그렇지 않을 수도 있습니다. 상대적으로 개선된 이 Java Virtual Machine 메모리 사양을 통해 Java Virtual Machine을 다양한 플랫폼에서 구현할 수 있습니다.
데이터 영역의 일부는 전체 프로그램에 공통되며 다른 부분은 별도의 스레드에 의해 제어됩니다. 각 JVM(Java Virtual Machine)에는 전체 프로그램에서 공유하는 메소드 영역과 힙이 포함되어 있습니다. JVM(Java Virtual Machine)은 클래스를 로드하고 구문 분석한 후 클래스 파일에서 구문 분석된 정보를 메소드 영역에 저장합니다. 프로그램이 실행될 때 생성된 객체는 힙에 저장됩니다.
스레드가 생성되면 자체 PC 레지스터 "pc 레지스터"(프로그램 카운터)와 Java 스택(Java 스택)이 할당됩니다. 스레드가 기본 메서드를 사용하지 않는 경우 PC 레지스터는 스레드가 실행하는 다음 명령을 저장합니다. Java 스택은 스레드가 로컬 변수, 호출 메소드의 매개변수, 반환 값 및 처리된 중간 변수를 포함하여 메소드를 호출할 때 상태를 저장합니다. 네이티브 메서드가 호출될 때의 상태는 네이티브 메서드 스택에 저장되며, 이는 레지스터나 플랫폼에 독립적이지 않은 기타 메모리에 있을 수 있습니다.
Java 스택은 스택 프레임(또는 프레임)으로 구성됩니다. 스택 블록에는 Java 메소드 호출 상태가 포함됩니다. 스레드가 메소드를 호출하면 JVM(Java Virtual Machine)은 새 블록을 Java 스택에 푸시합니다. 메소드가 끝나면 JVM(Java Virtual Machine)은 해당 블록을 팝하고 삭제합니다.
Java Virtual Machine은 중간 계산 결과를 저장하기 위해 레지스터를 사용하지 않지만 Java 스택을 사용하여 중간 결과를 저장합니다. 이는 Java Virtual Machine 명령을 더욱 간결하게 만들고 레지스터 없이 장치에서 Java Virtual Machine을 구현하는 것을 더 쉽게 만듭니다.
그림의 Java 스택에서 PC 레지스터의 스레드 3은 로컬 메소드를 실행 중이고 다음 실행 명령이 PC 레지스터에 저장되지 않기 때문에 아래쪽으로 성장하면서 회색으로 표시됩니다.
4. 데이터 유형
Java Virtual Machine에서 사용되는 모든 데이터에는 특정 데이터 유형이 있으며, 데이터 유형 및 작업은 Java Virtual Machine 사양에 엄격하게 정의되어 있습니다. Java의 데이터 유형은 기본 데이터 유형(기본 유형)과 참조 데이터 유형(참조 유형)으로 구분됩니다. 참조 유형은 실제 객체에 따라 달라지지만 객체 자체에는 의존하지 않습니다. 기본 데이터 유형은 어떤 것에도 의존하지 않으며 데이터 자체를 나타냅니다.
Java 프로그래밍 언어의 모든 기본 데이터 유형은 부울을 제외한 JVM(Java Virtual Machine)의 기본 데이터 유형입니다. 컴파일러는 Java 소스 코드를 자체 코드로 컴파일할 때 정수 유형(int) 또는 바이트 유형(byte)을 사용하여 Boolean 유형을 나타냅니다. Java 가상 머신은 부울 false를 나타내기 위해 정수 0을 사용하고 부울 true를 나타내기 위해 0이 아닌 정수를 사용합니다. 부울 배열은 힙의 바이트 배열 또는 비트 필드에 저장될 수 있지만 바이트 배열로 표현됩니다.
부울을 제외하고 Java 언어의 다른 기본 유형은 Java 가상 머신의 데이터 유형입니다. Java에서는 데이터 유형이 정수 바이트, short, int, char 및 부동 소수점 유형 float, double로 구분됩니다. Java 언어의 데이터 유형은 모든 호스트에서 동일한 범위를 갖습니다.
Java Virtual Machine에는 Java 언어에서 사용할 수 없는 원시 데이터 형식인 반환 값 형식(returnValue)도 있습니다. 이 유형은 Java 프로그램에서 "finally 절"을 구현하는 데 사용됩니다. 자세한 내용은 18장의 "Finally 절"을 참조하세요.
참조 유형은 클래스 유형, 인터페이스 유형, 배열 유형으로 생성될 수 있습니다. 모두 동적으로 생성된 객체를 참조합니다. 참조 유형이 null을 참조하면 참조되는 개체가 없다는 의미입니다.
Java Virtual Machine 사양은 각 데이터 유형이 나타내는 범위만 정의할 뿐, 저장 시 각 유형이 차지하는 공간은 정의하지 않습니다. 저장 방법은 Java 가상 머신의 구현자에게 달려 있습니다. 부동 소수점 유형에 대한 자세한 내용은 14장 "부동 소수점 산술"을 참조하세요.
TypeRange
byte8비트 부호 있는 2의 보수 정수(-27 ~ 27 - 1, 포함)
short16비트 부호 있는 2의 보수 정수(-215 ~ 215 - 1, 포함)
int32비트 부호 있는 2의 보수 정수(-231 ~ 231) 231 - 1 포함)
long64비트 부호 있는 2의 보수 정수(-263 ~ 263 - 1 포함)
char16비트 부호 없는 유니코드 문자(0 ~ 216 - 1 포함)
float32비트 IEEE 754 단정밀도 부동 소수점
이중 64비트 IEEE 754 배정밀도 부동소수점
동일 메소드 내 opcode의 반환값 주소
힙에 있는 객체에 대한 참조 참조 또는 null
5.바이트 길이
Java 가상 머신에서 가장 작은 데이터 단위 단어(워드), 그 크기는 Java 가상 머신의 구현자가 정의합니다. 그러나 한 단어의 크기는 byte, short, int, char, float, returnValue, reference를 수용하기에 충분해야 합니다. 두 단어는 long, double을 수용하기에 충분해야 합니다. 따라서 가상 머신의 구현자는 최소한 31비트보다 작은 워드를 제공해야 하지만, 특정 플랫폼에서는 가장 효율적인 워드 길이를 선택하는 것이 가장 좋습니다.
런타임에 Java 프로그램은 실행 중인 시스템의 단어 길이를 결정할 수 없습니다. 단어 길이는 프로그램의 동작에 영향을 미치지 않습니다. 이는 단지 Java 가상 머신의 표현 방식일 뿐입니다.
6. 클래스 로더 하위 시스템
Java 가상 머신에는 원시 클래스 로더와 클래스 로더 객체라는 두 가지 유형의 클래스 로더가 있습니다. 원래 클래스 로더는 JVM(Java Virtual Machine) 구현의 일부이고 클래스 로더 객체는 실행 중인 프로그램의 일부입니다. 서로 다른 클래스 로더에 의해 로드된 클래스는 서로 다른 네임스페이스로 구분됩니다.
클래스 로더는 Java 가상 머신의 다른 많은 부분과 java.lang 패키지의 많은 클래스를 호출합니다. 예를 들어, 클래스 로딩 객체는 java.lang.ClassLoader 하위 클래스의 인스턴스입니다. ClassLoader 클래스의 메소드는 Java 가상 머신에 의해 로드된 각 클래스가 Java로 표시되는 가상 머신의 클래스 로딩 메커니즘에 액세스할 수 있습니다. .lang.Class 클래스의 인스턴스입니다. 다른 객체와 마찬가지로 클래스 로더 객체와 Class 객체는 힙에 저장되고, 로드된 정보는 메소드 영역에 저장됩니다.
1. 로드, 연결 및 초기화
클래스 로드 하위 시스템은 클래스 파일을 찾고 로드할 뿐만 아니라 다음과 같은 엄격한 단계에 따라 다른 많은 작업도 수행합니다. (자세한 내용은 7장 "클래스 수명 주기" 참조)
1), 로딩: 지정된 타입(클래스 및 인터페이스)의 바이너리 정보를 찾아 가져오기
2), 연결: 검증, 준비 및 구문 분석
①검증: 가져온 타입이 올바른지 확인
② 준비: 타입에 대한 메모리 할당 그리고 기본값으로 초기화
③ 파싱 : 직접 마실 문자 참조를 파싱
3), 초기화 : 자바 코드를 호출하고 클래스 변수를 적절한 값으로 초기화
2. 원시 클래스 로더)
모든 자바 가상 머신 클래스 파일 형식을 준수하고 신뢰할 수 있는 클래스를 로드할 수 있는 기본 클래스 로더를 구현해야 합니다. 그러나 JVM(Java Virtual Machine)의 사양은 클래스를 로드하는 방법을 정의하지 않으며, 이는 JVM(Java Virtual Machine) 구현자가 결정하도록 남겨져 있습니다. 특정 유형 이름을 가진 유형의 경우 원래 로더는 유형 이름에 ".class"가 더해진 파일을 찾아 가상 머신에 로드해야 합니다.
3. 클래스 로더 객체
클래스 로더 객체는 Java 프로그램의 일부이지만 ClassLoader 클래스의 세 가지 메소드는 Java 가상 머신의 클래스 로딩 하위 시스템에 액세스할 수 있습니다.
1), protected final Class DefineClass(...): 이 메서드를 사용하여 바이트 배열에 액세스하고 새 유형을 정의합니다.
2) protected Class findSystemClass(String name): 지정된 클래스를 로드한 경우 직접 반환합니다.
3), protected final void receiveClass(Class c): DefineClass() 메서드는 클래스를 로드할 뿐입니다. 이 메서드는 후속 동적 연결 및 초기화를 담당합니다.
자세한 내용은 8장 "연결 모델"을 참조하세요.
4. 네임스페이스
여러 클래스 로더가 동일한 클래스를 로드하는 경우 이름의 고유성을 보장하기 위해 클래스를 로드하는 클래스 로더의 식별자를 클래스 이름 앞에 추가해야 합니다. 자세한 내용은 8장 "연결 모델"을 참조하세요.
7. 메소드 영역
Java Virtual Machine에서는 로드된 유형의 정보가 메소드 영역에 저장됩니다. 예를 들어, 가상 머신이 "리틀 엔디안" 프로세서에서 작동하는 경우 정보를 "리틀 엔디안" 형식으로 저장할 수 있습니다. Java 클래스 파일에서는 "big-endian" 형식으로 저장됩니다. 설계자는 프로그램이 가장 빠른 속도로 실행될 수 있도록 로컬 시스템에 가장 적합한 표현 형식으로 데이터를 저장할 수 있습니다. 그러나 메모리 양이 적은 장치에서는 가상 머신 구현자가 많은 양의 메모리를 점유하지 않습니다.
프로그램의 모든 스레드는 메소드 영역을 공유하므로 메소드 영역 정보에 액세스하는 방법은 스레드로부터 안전해야 합니다. Lava라는 클래스를 로드하는 스레드가 두 개 있는 경우 스레드 하나만 이 클래스를 로드할 수 있으며 다른 스레드는 기다려야 합니다.
프로그램이 실행 중일 때 메소드 영역의 크기는 가변적이며, 프로그램이 실행되는 동안 프로그램을 확장할 수 있습니다. 일부 Java 가상 머신 구현에서는 매개변수를 통해 메소드 영역의 초기 크기, 최소값 및 최대값을 사용자 정의할 수도 있습니다.
메소드 영역도 가비지 수집될 수 있습니다. 프로그램의 컨텐츠는 클래스 로더에 의해 동적으로 로드되므로 모든 클래스가 참조되지 않을 수 있습니다. 클래스가 이 상태가 되면 가비지 수집될 수 있습니다. 로드되지 않은 클래스에는 두 가지 상태가 포함됩니다. 하나는 실제로 로드되지 않은 상태이고 다른 하나는 "참조되지 않은" 상태입니다. 자세한 내용은 7장의 클래스 수명을 참조하세요.
1. 유형 정보
로드된 각 유형은 Java 가상 머신의 메소드 영역에 다음 정보를 저장합니다.
1) 유형의 정규화된 이름
2 ) 유형의 직접 슈퍼클래스의 정규화된 이름(예외) 상위 유형이 없거나 Frey 형식은 java.lang.Object입니다.) (유형의 직접 슈퍼클래스의 완전한 이름)
3) 주어진 유형이 클래스인지 인터페이스인지(클래스인지 인터페이스)인지(또는 유형이 클래스가 아님)
4), 유형 수정자(공용, 비공개, 보호, 정적, 최종, 휘발성, 임시 등)(유형 수정자)
5), 모든 상위 인터페이스 정규화된 순서가 지정된 목록 직접 슈퍼인터페이스의 이름 유형의 전체 이름으로 저장된 데이터 구조는 가상 머신 구현자가 정의합니다. 또한 Java Virtual Machine은 각 유형에 대해 다음 정보도 저장합니다.
1) 유형에 대한 상수 풀(The Constant Pool for the type)
2) 유형 필드 정보(Field information)
3) Method 정보
4), 상수를 제외한 타입에 선언된 모든 클래스(정적) 변수
5), 클래스 로더에 대한 참조(ClassLoader 클래스에 대한 참조)
6), Class Class(Class 클래스에 대한 참조) )
1) 타입에 대한 상수 풀(The Constant Pool for the Type)
상수 풀에 저장된 모든 타입은 문자열, 정수, 부동소수점 상수 등의 직접 상수(리터럴)를 포함하여 순서대로 배열된 상수 모음입니다. 유형, 필드 및 메소드에 대한 기호 참조. 상수 풀에 저장된 각 상수에는 배열의 필드와 마찬가지로 인덱스가 있습니다. 상수 풀은 상수 풀의 모든 타입이 사용하는 타입, 필드, 메소드에 대한 문자 참조를 저장하기 때문에 동적 연결의 주요 객체이기도 합니다. 자세한 내용은 6장 "Java 클래스 파일"을 참조하십시오.
2) 유형 필드 정보(필드 정보)
필드 이름, 필드 유형, 필드 수정자(공개, 비공개, 보호, 정적, 최종, 휘발성, 임시 등) 및 필드가 정의된 순서 수업.
3), 유형 메소드 정보(메소드 정보)
메소드 이름, 메소드 반환 값 유형(또는 void), 메소드 매개변수 수, 유형 및 해당 순서, 필드 수정자(public, private, protected, static, final, 휘발성, temporary) 등), 클래스에서 메소드가 정의되는 순서
추상적이고 로컬이 아닌 경우 이 메소드도 메소드의 바이트코드, 메소드의 피연산자 스택 크기 및 메소드의 크기를 저장해야 합니다. 지역 변수 영역(약간(자세한 내용은 추후 제공), 예외 목록(자세한 내용은 17장 "예외" 참조)
4), 클래스(정적) 변수(클래스 변수)
클래스 변수는 해당 클래스의 모든 인스턴스에서 공유됩니다. 클래스(클래스의 인스턴스를 통하지 않더라도)에도 액세스할 수 있습니다. 이러한 변수는 클래스의 인스턴스가 아닌 클래스에 바인딩되므로 클래스의 논리적 데이터의 일부입니다. Java 가상 머신이 이 클래스를 사용하기 전에 클래스 변수(non-final)에 대한 메모리 할당이 필요합니다. 상수(final)는 이 클래스 변수(non-final)와 처리 방법이 다릅니다. 각 유형이 상수를 사용하면 이를 자체 상수 풀에 복사합니다. 상수는 상수 풀에 저장된다는 점을 제외하면 클래스 변수와 마찬가지로 메서드 영역에도 저장됩니다. (아마도 클래스 변수는 모든 인스턴스에서 공유되는 반면 상수 풀은 각 인스턴스마다 고유합니다.) 최종이 아닌 클래스 변수는 이를 선언하는 유형에 대한 데이터의 일부로 저장되는 반면, 최종 상수는 이를 사용하는 모든 유형에 대한 데이터의 일부로 저장됩니다. 자세한 내용은 6장 "Java 클래스 파일Java 클래스 파일"을 참조하세요
5), ClassLoader 클래스에 대한 참조
Java 가상 머신에 의해 로드된 각 유형에 대해 가상 머신은 이 유형이 Original 클래스 로더인지 클래스 로더인지 저장해야 합니다. 로딩. 클래스 로더에 의해 로드된 유형은 클래스 로더에 대한 참조를 유지해야 합니다. 이 정보는 클래스 로더가 동적으로 연결할 때 사용됩니다. 클래스가 다른 클래스를 참조하는 경우 가상 머신은 참조된 유형이 동일한 클래스 로더에 의해 로드된다는 것을 저장해야 합니다. 이는 가상 머신이 서로 다른 네임스페이스를 유지하는 과정이기도 합니다. 자세한 내용은 8장 "링크 모델"
6), Class 클래스에 대한 참조
Java 가상 머신은 로드된 각 유형에 대해 java.lang.Class 클래스의 인스턴스를 생성합니다. 클래스 클래스 메서드인
public static Class forName(String className)을 사용하여 클래스를 찾거나 로드하고 해당 클래스 클래스의 인스턴스를 얻을 수도 있습니다. 이 클래스 클래스 인스턴스를 통해 Java 가상 머신의 메소드 영역에 있는 정보에 액세스할 수 있습니다. 자세한 내용은 Class 클래스의 JavaDoc을 참조하세요.
2. 메소드 테이블
메소드 영역에 저장된 모든 데이터에 보다 효율적으로 액세스하려면 이러한 데이터의 저장 구조를 신중하게 설계해야 합니다. 모든 메소드 영역에는 위의 원본 정보를 저장하는 것 외에도 메소드 목록과 같이 액세스 속도를 높이기 위해 설계된 데이터 구조도 있습니다. 로드된 각 비추상 클래스에 대해 JVM(Java Virtual Machine)은 해당 클래스에 대한 메소드 목록을 생성합니다. 이 목록은 이 클래스에서 호출할 수 있는 모든 인스턴스 메소드에 대한 참조를 저장하고 상위 클래스에서 호출된 메소드에 오류를 보고합니다. 자세한 내용은 8장 "링크 모델"을 참조하세요. 8. 힙
Java 프로그램은 클래스의 인스턴스나 배열을 생성할 때 힙에 새 개체에 대한 메모리를 할당합니다. 가상 머신에는 힙이 하나만 있고 모든 스레드가 이를 공유합니다.
1. 가비지 컬렉션
가비지 컬렉션은 참조되지 않은 객체를 해제하는 주요 방법입니다. 또한 힙 조각화를 줄이기 위해 개체를 이동할 수도 있습니다. 가비지 콜렉션은 JVM(Java Virtual Machine) 사양에 엄격하게 정의되어 있지 않지만 JVM(Java Virtual Machine) 구현이 어떤 방식으로든 자체 힙을 관리해야 한다고 정의되어 있습니다. 자세한 내용은 9장 "가비지 수집"을 참조하십시오.
2. 객체 저장 구조(객체 표현)
Java Virtual Machine의 사양은 객체가 힙에 저장되는 방식을 정의하지 않습니다. 각 객체는 주로 자신의 클래스와 부모 클래스에 정의된 객체 변수를 저장합니다. 특정 개체에 대한 참조를 위해 가상 머신은 이 개체의 데이터를 빠르게 찾아야 합니다. 또한 메소드 영역의 객체 참조와 같이 객체를 통해 메소드 객체 데이터를 참조할 수 있는 메소드가 제공되어야 하므로 객체가 저장한 데이터에는 어떤 형태로든 메소드 영역에 대한 포인터가 포함되는 경우가 많습니다.
가능한 힙 설계 중 하나는 힙을 참조 풀과 개체 풀의 두 부분으로 나누는 것입니다. 개체에 대한 참조는 참조 풀에 대한 로컬 포인터입니다. 참조 풀의 각 항목에는 두 부분, 즉 개체 풀의 개체 데이터에 대한 포인터와 메서드 영역의 개체 클래스 데이터에 대한 포인터가 포함됩니다. 이 디자인은 JVM(Java Virtual Machine) 힙의 조각 모음을 용이하게 할 수 있습니다. 가상 머신이 개체 풀의 개체를 이동할 때 해당 참조 풀의 포인터 주소만 수정하면 됩니다. 그러나 개체의 데이터에 액세스할 때마다 포인터를 두 번 처리해야 합니다. 아래 그림은 이 힙 설계를 보여줍니다. 9장 "가비지 수집"의 HeapOfFish 애플릿은 이 디자인을 보여줍니다.
또 다른 힙 설계는 개체의 참조가 데이터 더미를 가리키고 해당 개체를 가리키는 오프셋 포인터입니다. 이 디자인은 개체 액세스를 용이하게 하지만 개체 이동은 매우 복잡해집니다. 다음 그림은 이 디자인을 보여줍니다.
프로그램이 객체를 다른 유형으로 변환하려고 시도할 때 가상 머신은 변환이 객체의 유형인지 아니면 상위 유형인지 결정해야 합니다. 프로그램이 instanceof 문을 사용할 때도 비슷한 작업이 수행됩니다. 프로그램이 객체의 메소드를 호출할 때 가상 머신은 동적 바인딩을 수행해야 하며 호출할 메소드 유형을 결정해야 합니다. 이것도 위의 판단이 필요합니다.
가상머신 구현자는 어떤 디자인을 사용하더라도 객체별로 메소드 목록과 유사한 정보를 저장할 수 있습니다. 객체 메서드 호출 속도를 높일 수 있기 때문에 가상 머신의 성능을 향상시키는 것이 매우 중요합니다. 그러나 가상 머신 사양에는 유사한 데이터 구조를 구현해야 한다는 요구 사항이 없습니다. 아래 다이어그램은 이 구조를 보여줍니다. 그림은
1), 유형 데이터에 대한 포인터
2) 및 개체의 메서드 목록을 포함하여 개체 참조와 관련된 모든 데이터 구조를 보여줍니다. 메소드 목록은 객체에서 호출될 수 있는 모든 메소드에 대한 포인터 배열입니다. 메소드 데이터에는 opcode 스택의 크기, 메소드 스택의 로컬 변수 영역 및 예외 목록의 세 부분이 포함됩니다.
Java Virtual Machine의 모든 개체는 여러 스레드를 동기화하는 데 사용되는 잠금(뮤텍스)과 연결되어야 합니다. 동시에 단 하나의 객체만이 이 객체의 잠금을 보유할 수 있습니다. 개인이 이 물건의 자물쇠를 소유한 경우 그는 여러 번 자물쇠를 신청할 수 있지만 실제로 물건 자물쇠를 해제하려면 해당 횟수만큼 자물쇠를 해제해야 합니다. 많은 객체는 수명 내내 잠겨 있지 않으므로 이 정보는 필요할 때만 추가하면 됩니다. 많은 JVM(Java Virtual Machine) 구현은 객체 데이터에 "잠금 데이터"를 포함하지 않으며 필요할 때만 해당 데이터를 생성합니다. 객체 잠금 구현 외에도 각 객체는 "대기 세트" 구현과 논리적으로 연결됩니다. 잠금은 그룹 스레드가 다른 스레드를 방해하지 않고 독립적으로 공유 데이터를 처리하는 데 도움이 됩니다. "대기 설정"은 그룹 스레드가 협력하여 동일한 목표를 달성하는 데 도움이 됩니다. "대기 설정"은 Object 클래스의 wait() 및 inform() 메서드를 통해 구현되는 경우가 많습니다.
가비지 수집에는 힙의 개체가 연결되어 있는지 여부에 대한 정보도 필요합니다. Java Virtual Machine 사양에는 가비지 수집이 개체의 종료자 메서드를 한 번 실행하지만 개체가 다시 참조되지 않으면 종료자 메서드를 다시 호출할 필요가 없다고 명시되어 있습니다. 따라서 가상 머신은 finalize 메서드가 실행되었는지 여부에 대한 정보도 저장해야 합니다. 자세한 내용은 9장의 "가비지 수집"을 참조하세요.
3. 배열 저장(배열 표현)
Java에서 배열은 객체처럼 힙에 저장되며 클래스 A 참조에 대한 포인터를 갖습니다. 클래스 인스턴스에. 동일한 차원과 유형의 모든 배열은 동일한 클래스를 가지며 배열의 길이는 고려되지 않습니다. Class에 해당하는 이름을 차원과 타입으로 표현합니다. 예를 들어 정수 데이터의 클래스 이름은 "[I"이고, 바이트형 3차원 배열의 클래스 이름은 "[[[B"", 2차원 객체 데이터의 클래스 이름은 "[[ Ljava.lang.Object".
다차원 배열은 아래와 같이 배열의 배열로 표현됩니다.
배열은 배열의 길이, 배열의 데이터 및 객체 배열 유형 데이터에 대한 일부 참조를 힙에 저장해야 합니다. 배열 참조를 통해 가상 머신은 배열의 길이를 얻을 수 있어야 하고, 인덱싱을 통해 특정 데이터에 액세스하고, Object에서 정의한 메서드를 호출할 수 있어야 합니다. 객체는 모든 데이터 클래스의 직접적인 상위 클래스입니다. 자세한 내용은 6장 "클래스 파일"을 참조하십시오.
9. PC 레지스터(프로그램 카운터)(The Program Counter)
각 스레드가 실행을 시작할 때 프로그램 카운터가 생성됩니다. 프로그램 카운터는 단 한 단어 길이이므로 로컬 포인터와 returnValue를 보유할 수 있습니다. 스레드가 실행될 때 프로그램 카운터는 실행 중인 명령어의 주소를 저장합니다. 이 주소는 로컬 포인터이거나 메서드 바이트코드에서 시작하는 오프셋 포인터일 수 있습니다. 네이티브 메소드가 실행되면 프로그램 카운터 값이 정의되지 않습니다.
10. Java 스택
스레드가 시작되면 Java 가상 머신은 이에 대한 Java 스택을 생성합니다. Java 스택은 일부 개별 프레임 클래스를 사용하여 스레드 상태를 기록합니다. Java 가상 머신 힙 Java 스택에는 프레임 푸시 및 팝핑이라는 두 가지 작업만 있습니다.
스레드에서 실행 중인 메서드를 현재 메서드라고 하며, 현재 메서드에 해당하는 프레임을 현재 프레임이라고 합니다. 현재 메서드를 정의하는 클래스를 현재 클래스라고 하며, 현재 클래스의 상수 풀을 현재 상수 풀이라고 합니다. 스레드가 실행될 때 Java 가상 머신은 현재 클래스와 현재 상수 풀을 추적합니다. 그러나 스레드가 프레임에 저장된 데이터에 대해 작동하는 경우 현재 프레임의 데이터에 대해서만 작동합니다.
스레드가 메소드를 호출하면 가상 머신은 새 프레임을 생성하고 이를 스레드의 Java 스택에 푸시합니다. 이 새 프레임이 현재 프레임이 됩니다. 메서드가 실행되면 현재 프레임을 사용하여 메서드의 매개변수, 지역 변수, 중간 구조 및 기타 데이터를 저장합니다. 메소드에는 정상 종료와 비정상 종료의 두 가지 종료 방법이 있습니다. 메소드가 어떤 방식으로 실행되든 JVM(Java Virtual Machine)은 팝업되어 메소드의 프레임을 버리고 이전 메소드의 프레임이 현재 프레임이 됩니다.
프레임에 저장된 모든 데이터는 해당 프레임을 소유한 스레드에서만 액세스할 수 있습니다. 스레드는 다른 스레드의 스택에 있는 데이터에 액세스할 수 없습니다. 따라서 메소드의 지역 변수에 접근할 때 멀티스레드 동기화를 고려할 필요가 없습니다.
메서드 영역 및 힙과 마찬가지로 Java 스택은 지속적인 메모리 공간을 필요로 하지 않으며 분산 메모리 공간이나 힙에 저장할 수 있습니다. 스택의 특정 데이터와 길이는 Java 가상 머신의 구현자가 정의합니다. 일부 구현에서는 스택 최대화 및 최소화를 수행하는 방법을 제공할 수 있습니다.
11. 스택 프레임
스택 프레임은 로컬 변수, 피연산자 스택 및 프레임 데이터의 세 부분으로 구성됩니다. 지역 변수와 피연산자 스택의 크기는 단어 단위로 측정되며 컴파일 중에 결정됩니다. 프레임 데이터의 크기는 구현에 따라 다릅니다. 프로그램이 메소드를 호출하면 가상 머신은 클래스 데이터로부터 지역 변수와 피연산자 스택의 크기를 얻어 적절한 크기와 프레임을 생성한 후 이를 Java 스택에 푸시합니다.
1. 로컬 변수
로컬 변수는 Java 스택 프레임에서 0부터 계산되는 배열로 구성됩니다. 명령어는 인덱스를 제공하여 로컬 변수 영역에서 해당 값을 얻습니다. Int, float, reference, returnValue는 1워드를 차지하고, byte, short, char는 int로 변환하여 저장하며, long, doublel은 2워드를 차지합니다.
명령은 두 단어 인덱스 중 첫 번째 인덱스를 제공하여 long 또는 double 값을 얻습니다. 예를 들어 인덱스 3이나 4에 Long 값이 저장되어 있다면 명령어는 3을 통해 Long 값을 얻을 수 있다.
로컬 변수 영역에는 메소드 매개변수와 로컬 변수가 포함됩니다. 컴파일러는 메소드 매개변수를 선언된 순서대로 배열 앞에 배치합니다. 그러나 컴파일러는 지역 변수 배열에서 지역 변수를 임의로 배열할 수 있으며 두 지역 변수도 공통 주소를 공유할 수 있습니다. 예를 들어 루프 변수 i,j와 같이 두 지역 변수가 두 개의 겹치지 않는 영역에 있는 경우입니다.
가상 머신의 구현자는 로컬 변수 영역의 데이터를 설명하기 위해 어떤 구조를 사용할 수 있습니다. 가상 머신 사양은 long 및 doublel을 저장하는 방법을 정의하지 않습니다.
2. 피연산자 스택(Operand Stack)
로컬 변수와 마찬가지로 피연산자 스택도 워드 단위의 배열로 구성됩니다. 하지만 지역 변수처럼 인덱스를 통해서 접근하는 것이 아니라, push와 pop 값을 통해서 접근합니다. 한 명령어가 스택에 값을 푸시하면 다음 명령어가 해당 값을 팝하여 사용할 수 있습니다.
프로그램 카운터와 달리 명령어는 피연산자 스택에 직접 액세스할 수 없습니다. JVM(Java Virtual Machine)은 명령어가 동일한 레지스터가 아닌 스택에서 피연산자를 가져오기 때문에 레지스터 기반이 아닌 스택 기반입니다. 물론 명령어는 명령어 뒤의 opcode나 상수 풀과 같은 다른 위치에서 피연산자를 가져올 수도 있습니다. 그러나 Java 가상 머신 명령어는 주로 피연산자 스택에서 필요한 피연산자를 얻습니다.
Java 가상 머신은 피연산자 스택을 작업 영역으로 처리합니다. 많은 명령어가 먼저 피연산자 스택에서 값을 팝한 다음 처리 후 결과를 다시 피연산자 스택으로 푸시합니다. add 명령어의 실행 프로세스는 아래 그림에 나와 있습니다. 먼저 iload_0 및 iload_1 명령어를 실행하여 로컬 메서드 영역에서 추가해야 하는 두 숫자를 가져와 피연산자 스택에 푸시한 다음 iadd 명령어를 실행합니다. 이제 두 개의 값을 출력하고 이를 추가한 후 결과를 피연산자 스택에 푸시합니다. 마지막으로 istore_2 명령어를 실행하고 결과를 팝하여 로컬 메서드 영역에 할당합니다.
3. 프레임 데이터
Java 스택 프레임에는 로컬 변수 및 피연산자 스택 처리 외에도 상수 풀, 메서드 반환 값 및 예외 배포를 지원하는 데 필요한 데이터도 포함되어 있으며 프레임 데이터에 저장됩니다.
가상 머신이 상수 풀에 대한 참조를 사용하는 명령어를 발견하면 프레임 데이터의 상수 영역에 대한 포인터를 통해 필요한 정보에 액세스합니다. 앞에서 언급했듯이 상수 영역의 참조는 시작 부분의 상징적 참조입니다. 가상 머신이 이러한 참조를 확인하는 경우에도 문자 참조입니다. 따라서 가상 머신은 이때 이 참조를 변환해야 합니다.
메서드가 정상적으로 반환되면 가상 머신은 이 메서드를 호출한 메서드의 스택 프레임을 재구성해야 합니다. 실행된 메서드에 반환 값이 있는 경우 가상 머신은 이 값을 호출 메서드의 피연산자 스택에 푸시해야 합니다.
프레임 데이터에는 예외를 처리하기 위해 가상 머신에서 사용하는 예외 테이블에 대한 참조도 포함되어 있습니다. 예외 테이블은 catch 문으로 보호되는 바이트코드 섹션을 정의합니다. 예외 테이블의 각 개별에는 보호해야 할 바이트 코드 범위와 예외가 발견될 때 실행해야 하는 바이트 코드의 위치도 포함되어 있습니다. 메소드가 예외를 발생시키면 JVM(Java Virtual Machine)은 예외 테이블을 사용하여 예외 처리 방법을 결정합니다. 가상 머신이 일치하는 catch를 찾으면 제어권을 catch 문으로 이전합니다. 일치하는 catch가 없으면 메서드가 비정상적으로 반환된 다음 호출 메서드에서 프로세스를 계속합니다.
위의 세 가지 용도 외에도 프레임 데이터에는 디버깅 정보와 같은 구현에 따른 일부 데이터가 포함될 수도 있습니다.
12. 로컬 메서드 스택
로컬 메서드 영역은 가상 머신의 다양한 구현에 따라 다릅니다. 가상 머신의 구현자는 기본 메소드를 실행하는 데 사용할 메커니즘을 결정할 수 있습니다.
모든 기본 메서드 인터페이스는 기본 메서드 스택 형식을 사용합니다.
13. 실행 엔진
Java 가상 머신 구현의 핵심은 실행 엔진입니다. Java Virtual Machine 사양에서 실행 엔진은 일련의 명령으로 설명됩니다. 각 지시문에 대해 사양에서는 수행해야 할 작업을 설명하지만 수행 방법은 설명하지 않습니다.
1. 명령어 세트
Java Virtual Machine에서 메소드의 바이트코드 스트림은 일련의 명령어입니다. 각 명령어는 바이트 연산 코드(Opcode)와 가능한 피연산자(Operands)로 구성됩니다. opcode는 수행할 작업을 알려주고 피연산자는 opcode를 실행하는 데 필요할 수 있는 몇 가지 추가 정보를 제공합니다. 추상 실행 엔진은 한 번에 하나의 명령어를 실행합니다. 이 프로세스는 모든 실행 스레드에서 발생합니다.
때때로 실행 엔진은 로컬 메서드 호출이 필요한 명령을 만날 수 있습니다. 이 경우 실행 엔진은 로컬 메서드 호출을 시도하지만 로컬 메서드가 반환되면 실행 엔진은 계속해서 다음 단계를 실행합니다. 바이트코드 스트림. 네이티브 메소드는 JVM(Java Virtual Machine)의 명령어 세트를 확장한 것으로 볼 수도 있습니다.
다음에 실행할 명령을 결정하는 것도 실행 엔진 작업의 일부입니다. 실행 엔진에는 다음 명령을 얻는 세 가지 방법이 있습니다. 대부분의 명령어는 뒤에 오는 명령어를 실행합니다. goto 및 return과 같은 일부 명령어는 명령어가 예외를 발생시킬 때 다음 명령어를 결정하며, 실행 엔진은 catch 문을 일치시켜 다음 명령어를 결정합니다. 처형되다.
플랫폼 독립성, 네트워크 이동성 및 보안은 Java 가상 머신 명령어 세트의 설계에 영향을 미칩니다. 플랫폼 독립성은 명령어 세트 설계에 영향을 미치는 주요 요인 중 하나입니다. 스택 기반 구조를 통해 Java Virtual Machine을 더 많은 플랫폼에서 구현할 수 있습니다. 더 작은 opcode와 컴팩트한 구조를 통해 바이트코드는 네트워크 대역폭을 보다 효율적으로 활용할 수 있습니다. 일회성 바이트코드 확인을 통해 성능에 큰 영향을 주지 않으면서 바이트코드를 더욱 안전하게 만들 수 있습니다.
2. 실행 기술
Java 가상 머신 구현에는 해석된 실행, JIT(Just-In-Time) 컴파일, 핫스팟 컴파일, 실리콘의 기본 실행 등 다양한 실행 기술이 사용될 수 있습니다.
3. 스레드
Java Virtual Machine 사양은 더 많은 플랫폼에서 구현하기 위한 스레딩 모델을 정의합니다. Java 스레딩 모델의 한 가지 목표는 기본 스레드를 활용하는 것입니다. 로컬 스레드를 사용하면 Java 프로그램의 스레드가 다중 프로세서 시스템에서 동시에 실행될 수 있습니다.
Java 스레딩 모델의 비용 중 하나는 스레드 우선순위입니다. Java 스레드는 1-10의 우선순위 수준에서 실행될 수 있습니다. 1이 가장 낮고 10이 가장 높습니다. 디자이너가 네이티브 스레드를 사용했다면 이러한 10가지 우선순위를 로컬 우선순위에 매핑했을 것입니다. JVM(Java Virtual Machine) 사양은 우선 순위가 높은 스레드가 CPU 시간을 얻을 수 있다고 정의하고, 우선 순위가 높은 스레드가 모두 차단될 때 우선 순위가 낮은 스레드도 CPU 시간을 얻을 수 있다고 정의하지만 보장은 없습니다. 우선 순위가 낮은 스레드는 CPU 시간을 얻을 수 없습니다. 우선순위가 높은 스레드가 차단되지 않을 때 일정량의 CPU 시간. 따라서 서로 다른 스레드 간 협력이 필요한 경우 "synchronizatoin"을 사용해야 합니다.
동기화는 객체 잠금과 스레드 대기 및 알림의 두 부분을 의미합니다. 개체 잠금은 스레드가 다른 스레드의 간섭으로부터 자유로운 상태를 유지하는 데 도움이 됩니다. 스레드 대기 및 활성화를 통해 서로 다른 스레드가 협력할 수 있습니다.
Java Virtual Machine의 사양에서는 Java 스레드를 변수, 메인 메모리, 작업 메모리로 설명합니다. JVM(Java Virtual Machine)의 각 인스턴스에는 객체, 배열, 클래스 변수 등 모든 프로그램 변수를 포함하는 주 메모리가 있습니다. 각 스레드에는 자체 작업 메모리가 있으며 사용할 수 있는 변수의 복사본을 보관합니다. 규칙:
1) 메인 메모리에서 작업 메모리로 변수 값을 복사합니다.
2) 작업 메모리의 값을 메인 메모리에 씁니다.
변수가 동기화되지 않으면 스레드가 메인 메모리를 업데이트할 수 있습니다. 어떤 순서로든 변수. 다중 스레드 프로그램의 올바른 실행을 보장하려면 동기화 메커니즘을 사용해야 합니다.
14. 네이티브 메소드 인터페이스(Native Method Interface)
Java Virtual Machine의 구현은 네이티브 메소드 인터페이스를 구현할 필요가 없습니다. 일부 구현에서는 기본 메서드 인터페이스를 전혀 지원하지 않을 수 있습니다. Sun의 기본 메소드 인터페이스는 JNI(Java Native Interface)입니다.
15. 실제 기계
16. 수학적 방법: 시뮬레이션(영원한 수학: 시뮬레이션)
위 내용은 JVM(Java Virtual Machine) 지식 포인트 소개의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!