>  기사  >  Java  >  Java Virtual Machine Learning - 클래스 로딩 메커니즘

Java Virtual Machine Learning - 클래스 로딩 메커니즘

黄舟
黄舟원래의
2017-03-18 17:51:551249검색

클래스 로딩 메커니즘

로딩 메커니즘은 JVM이 클래스 파일을 메모리에 로드하고 데이터를 검증, 변환, 구문 분석 및 초기화한 후 최종적으로 직접 사용할 수 있는 Java 유형을 형성하는 프로세스입니다. JVM에서 사용됩니다.

클래스는 가상 머신 메모리에 로드된 후 메모리에서 언로드될 때까지 시작됩니다. 클래스의 수명 주기에는 로딩, 확인, 준비, 해결, 초기화, 사용, 언로드의 7단계가 있습니다. 그 중 검증, 준비, 구문 분석의 세 부분을 총칭하여 링크라고 합니다.

로딩(로딩), 검증, 준비, 초기화, 언로딩의 5단계 순서가 정해져 있으며, 클래스의 로딩 과정은 반드시 이 순서대로 시작되어야 합니다. 구문 분석 단계 반드시 그런 것은 아닙니다. 런타임 동적 바인딩 기능을 위해 초기화 후에 시작될 수도 있습니다. 이러한 단계는 일반적으로 혼합 방식으로 수행되며 일반적으로 한 단계가 실행되는 동안 다른 단계를 호출하거나 활성화한다는 점에 주목할 가치가 있습니다.


로딩:

로딩 단계는 "클래스 로딩 메커니즘"의 한 단계이며 일반적으로 "로딩"이라고도 하며 주로 다음을 완료합니다.

1. "클래스의 전체 이름"을 통해 이 클래스를 정의하는 바이너리 바이트 스트림을 가져옵니다.

2. 메소드에서 바이트 스트림으로 표시되는 정적 저장 구조를 런타임 데이터로 변환합니다. 영역 구조

3. 메소드 영역에서 이러한 데이터에 대한 액세스 항목으로 Java 힙에서 이 클래스를 나타내는 java.lang.Class 객체를 생성합니다.

가상 머신 사양은 "를 통해"입니다. " 클래스의 전체 이름 "이 클래스를 정의하는 이진 바이트 스트림을 얻으려면"은 이진 스트림을 로컬 클래스 파일에서 가져와야 함을 지정하지 않습니다. 정확하게 말하면 이를 얻는 위치와 방법을 지정하지 않습니다. 예:

Zip 패키지에서 읽는 것은 매우 일반적이며 결국 향후 JAR, EAR 및 WAR 형식의 기초가 됩니다.

인터넷에서 구함, 공통 애플리케이션 애플릿.

런타임 계산 및 생성. 이 시나리오에서 가장 일반적으로 사용되는 기술은 java.lang.reflect.Proxy에서 ProxyGenerator.generateProxyClass를 사용하여 $Prxoy의 프록시 클래스 바이너리를 생성합니다. 특정 인터페이스.

은 다른 형식의 파일에서 생성됩니다. 일반적인 시나리오: JSP 애플리케이션

은 데이터베이스에서 읽습니다. 이 시나리오는 상대적으로 드물며 일부 미들웨어 서버(예: SAP Netweaver)는 프로그램을 설치하도록 선택할 수 있습니다. 클러스터 간에 프로그램 코드 배포를 완료하기 위해 데이터베이스에.

클래스 로딩 프로세스의 다른 단계에 비해 로딩 단계(준비 말하기, 로딩 단계에서 클래스의 바이너리 바이트 스트림을 얻는 작업)는 개발 기간 동안 가장 제어하기 쉬운 단계입니다. 로딩 단계 이는 시스템에서 제공하는 클래스 로더(ClassLoader)를 사용하여 수행할 수도 있고, 사용자 정의 클래스 로더를 사용하여 수행할 수도 있습니다. 개발자는 자신의 클래스 로더를 정의하여 바이트 스트림의 획득 방법을 제어할 수 있습니다.

로딩 단계가 완료된 후 가상 머신 외부의 바이너리 바이트 스트림은 가상 머신에서 요구하는 형식에 따라 메소드 영역에 저장됩니다. 메소드 영역의 데이터 저장 형식은 가상 머신에 의해 정의됩니다. 머신 구현. 가상 머신 이 영역의 특정 데이터 구조는 지정되지 않습니다. 그런 다음 java.lang.Class 클래스의 객체가 Java 힙에서 인스턴스화됩니다. 이 객체는 프로그램이 메소드 영역에서 이러한 유형의 데이터에 액세스하기 위한 외부 인터페이스 역할을 합니다. 로딩 단계와 링크 단계(예: 일부 바이트코드 파일 형식 확인 작업)의 일부가 인터리브됩니다. 로딩 단계가 아직 완료되지 않았으며 링크 단계가 시작되었을 수 있지만 로딩 단계 사이에 끼어 있는 이러한 작업은 여전히 ​​에 속합니다. 링크. 스테이지의 내용과 이 두 스테이지의 시작 시간은 여전히 ​​고정된 순서를 유지합니다.


확인:

확인은 연결 단계의 첫 번째 단계입니다. 이 단계의 주요 목적은 클래스 파일의 바이트 스트림에 포함된 정보가 현재 가상 머신의 요구 사항을 충족하는지 확인하는 것입니다. 가상 머신 자체의 보안을 위협하지 않습니다.

검증 단계에는 주로 파일 형식 검증, 메타데이터 검증, 바이트코드 검증, 기호 참조 검증의 4가지 검증 프로세스가 포함됩니다.

1. 파일 형식 확인

클래스 파일 형식 사양을 확인합니다. 예: 클래스 파일이 매직 0xCAFEBABE로 시작하는지, 메이저 및 마이너 버전 번호가 처리 범위 내에 있는지 여부

2. 메타데이터 검증

바이트코드로 기술된 정보에 대한 의미 분석을 수행하여 기술된 정보가 Java 언어 사양의 요구 사항을 충족하는지 확인하는 단계입니다. . 검증 포인트에는 다음이 포함될 수 있습니다: 이 클래스에 상위 클래스가 있는지 여부(java.lang.Object를 제외하고 모든 클래스에는 상위 클래스가 있어야 함), 이 클래스가 상속이 허용되지 않는 클래스를 상속하는지(final에 의해 수정됨) 이 클래스의 상위 클래스는 추상 클래스입니다. 상위 클래스 또는 인터페이스에서 구현하는 데 필요한 모든 메서드를 구현합니까?

3. 바이트코드 검증

데이터 흐름 및 제어 흐름 분석을 수행합니다. 이 단계에서는 클래스의 메서드 본문을 검증하고 분석합니다. 이 단계의 작업은 검증되는 클래스의 메서드가 클래스를 위험에 빠뜨리는 작업을 수행하지 않도록 하는 것입니다. 런타임 중 가상 머신의 보안. 예를 들어, 액세스 메소드 본문의 유형 변환이 유효한지 확인하십시오. 예를 들어, 하위 클래스 객체를 상위 클래스 데이터 유형에 할당할 수는 있지만 상위 클래스 객체를 하위 클래스 데이터 유형에 할당할 수는 없습니다. 점프 명령이 메소드 본문 외부의 바이트코드 명령으로 점프하지 않는지 확인하십시오.

4. 기호 참조 확인

기호 참조의 문자열로 기술된 정규화된 이름이 해당 클래스를 찾을 수 있는지 여부, 기호 참조 클래스의 클래스, 필드 및 메서드에 대한 접근성 (private, protected, public, default)는 현재 클래스에서 액세스할 수 있습니다.


준비:

준비 단계는 클래스 변수에 대한 메모리를 정식으로 할당하고 클래스 변수의 초기값을 설정하는 단계입니다. 배포 방법 영역에서 수행됩니다. 이 단계에서 쉽게 혼동될 수 있는 두 가지 지식이 있습니다. 첫째, 현재 메모리 할당에는 인스턴스 변수가 아닌 클래스 변수(정적 수정 변수)만 포함됩니다. 자바 힙. 둘째, 여기서 언급된 초기 값은 "일반적으로" 데이터 유형의 0 값입니다. 클래스 변수가 다음과 같이 정의되었다고 가정합니다.

public static int value = 12;

그런 다음 변수 값은 다음과 같습니다. 아직 Java 메소드가 실행되지 않았기 때문에 준비 단계 이후의 초기 값은 12가 아닌 0이며, 123에 값을 할당하는 putstatic 명령은 프로그램 컴파일 후 클래스 생성자 () 메소드에 저장됩니다. . 이므로 12에 값을 할당하는 작업은 초기화 단계에서만 실행됩니다.

위에서 언급한 "일반적인 상황"에서는 초기 값이 0입니다. 일부 특수한 경우와 비교하여 클래스 필드의 필드 속성 테이블에 ConstantValue 속성이 있으면 변수 값이 변경됩니다. 준비 단계에서 ConstantValue 속성에 의해 지정된 값으로 초기화되고 위의 클래스 변수 값은 다음과 같이 정의됩니다.

public static final int value = 123;

컴파일 시 javac가 생성됩니다. 값에 대한 ConstantValue 속성 준비 중 스테이지 가상 머신은 ConstantValue 설정에 따라 값을 123으로 설정합니다.


파싱:

파싱 단계는 가상 머신 상수 풀의 기호 참조를 직접 참조로 바꾸는 프로세스입니다.

기호 참조: 기호 참조는 참조된 대상 개체를 설명하는 기호 집합입니다. 기호는 사용 시 대상을 명확하게 찾을 수 있는 한 모든 형태의 리터럴이 될 수 있습니다. 기호 참조는 가상 머신이 구현하는 메모리 레이아웃과 아무 관련이 없으며 참조된 대상 개체를 반드시 메모리에 로드할 필요는 없습니다.

직접 참조: 직접 참조는 대상 개체를 직접 가리키는 포인터, 상대 오프셋 또는 대상을 간접적으로 찾을 수 있는 핸들일 수 있습니다. 직접 참조는 가상 머신 메모리 레이아웃 구현과 관련됩니다. 서로 다른 가상 머신 인스턴스의 동일한 기호 참조에서 변환된 직접 참조는 일반적으로 동일하지 않습니다. 직접 참조가 메모리에 이미 존재해야 합니다.

가상 머신 사양에서는 구문 분석 단계가 발생하는 특정 시간을 규정하지 않습니다. anewarry, checkcast, getfield, instanceof, Invokeinterface, Invokespecial, Invokestatic, Invokevirtual, Multianewarray, New의 13단계만 실행하면 됩니다. , putfield 및 putstatic 기호 참조를 작동하는 데 사용되는 바이트코드 명령어 전에 사용되는 기호 참조가 먼저 구문 분석되므로 가상 머신 구현은 클래스가 로드될 때 상수 풀의 기호 참조가 처리되는지 여부를 필요에 따라 판단합니다. 로더를 구문 분석하거나 기호 참조를 구문 분석하기 전에 사용할 때까지 기다리십시오.

파싱 작업은 주로 클래스 또는 인터페이스, 필드, 클래스 메서드, 인터페이스 메서드의 네 가지 유형의 기호 참조에 대해 수행됩니다. 컴파일된 상수 풀의 네 가지 상수 유형 CONSTANT_Class_Info, CONSTANT_Fieldref_Info, CONSTANT_Methodef_Info 및 CONSTANT_InterfaceMethoder_Info에 각각 해당합니다.

1. 클래스 및 인터페이스 분석

2. 필드 분석

3. 클래스 메소드 분석

4. >


초기화:

클래스 초기화 단계는 클래스 로딩 프로세스의 마지막 단계로, 준비 단계에서 클래스 변수에 초기 값이 할당되었습니다. 시스템이 요구하는 값으로, 초기화 단계에서는 프로그래머가 프로그램을 통해 작성한 주관적인 계획에 따라 클래스 변수 및 기타 자원을 초기화하거나, 또 다른 관점에서 표현할 수도 있다. 초기화 단계는 다음과 같은 과정이다. 클래스 생성자 () 메소드를 실행합니다. 초기화 프로세스는 다음 네 가지 상황에서 트리거됩니다.

1. new, getstatic, putstatic 또는 Invokestatic의 네 가지 바이트코드 명령어가 발생할 때 클래스가 초기화되지 않은 경우 먼저 트리거되어야 합니다. 초기화. 이러한 네 가지 명령어를 생성하는 가장 일반적인 Java 코드 시나리오는 new 키워드를 사용하여 객체를 인스턴스화하는 것, 클래스의 정적 필드를 읽거나 설정하는 것입니다(final에 의해 수정되고 상수 풀에 추가된 정적 필드는 제외). 컴파일러)) 및 클래스의 정적 메서드를 호출할 때.

2. java.lang.reflect 패키지의 메소드를 사용하여 클래스에 대한 반사 호출을 수행하는 경우

3. 클래스를 초기화할 때 해당 상위 클래스에 초기화되지 않았습니다. 먼저 상위 클래스를 초기화해야 합니다

4. jvm이 시작되면 사용자가 실행할 메인 클래스(메인 메소드를 포함하는 클래스)를 지정하고 가상 머신은 이 클래스를 먼저 초기화합니다.

위 준비 단계에서 public static int value = 12; 준비 중 단계가 완료된 후 value의 값은 0이고 초기화 단계에서 클래스 생성자 () 메서드가 호출됩니다.

*클래스 생성자() 메소드는 클래스 내 모든 클래스 변수의 할당 동작을 자동으로 수집하고 정적 명령문 블록(정적 블록)의 명령문을 병합하는 컴파일러에 의해 생성됩니다. 순서는 소스 파일에 문장이 나타나는 순서에 따라 결정됩니다. 정적 문장 블록에서는 정적 문장 블록 이전에 정의된 변수에만 접근할 수 있으며, 이후에 정의된 변수에는 이전 정적 문장에서 값을 할당할 수 있습니다. , 하지만 액세스할 수 없습니다.

* 클래스 생성자() 메서드는 클래스 생성자(인스턴스 생성자() 메서드)와 다릅니다. 상위 클래스 생성자를 명시적으로 호출할 필요가 없습니다. 하위 클래스의 () 메서드가 실행되기 전에 부모 클래스의 () 메서드가 실행되었습니다. 따라서 가상머신에서 실행되는 첫 번째 () 메소드의 클래스는 java.lang.Object이어야 한다.

* 상위 클래스의 () 메소드가 먼저 실행되므로 상위 클래스에 정의된 정적 명령문이 하위 클래스의 변수 할당 작업보다 우선한다는 의미입니다.

*() 메서드는 클래스나 인터페이스에 필요하지 않습니다. 클래스에 정적 문이 없고 변수 할당 작업이 없으면 컴파일러는 이 클래스에 대해 <를 생성할 필요가 없습니다. clinit>() 메서드입니다.

* 인터페이스에서는 정적 문 블록을 사용할 수 없지만 인터페이스와 클래스에서는 불가능합니다. 인터페이스의 () 메서드를 실행할 때 먼저 (()를 실행할 필요가 없다는 점입니다. ) 상위 인터페이스의 메서드입니다. 상위 인터페이스는 상위 인터페이스에 정의된 변수가 사용될 때만 초기화됩니다. 또한 인터페이스의 구현 클래스는 초기화 중에 인터페이스의 () 메서드를 실행하지 않습니다.

* 가상 머신은 다중 스레드 환경에서 클래스의 () 메서드가 올바르게 잠기고 동기화되도록 보장합니다. 여러 스레드가 동시에 클래스를 초기화하는 경우 하나의 스레드만 초기화됩니다. 이것을 실행하십시오. 클래스의 () 메소드의 경우 다른 스레드는 활성 스레드가 () 메소드 실행을 완료할 때까지 차단하고 대기해야 합니다. 클래스의 () 메서드에 장기 실행 작업이 있는 경우 여러 프로세스가 차단될 수 있습니다.

위 내용은 Java Virtual Machine Learning - Class Loading Mechanism의 내용입니다. 더 많은 관련 내용은 PHP 중국어 홈페이지(www.php.cn)를 참고해주세요!

관련기사 :

Java Virtual Machine에 대한 자세한 설명

Java Virtual Machine에 대한 심층적인 이해

Java Virtual Machine Learning - 객체 메모리 할당 및 재활용

Java Virtual Machine Learning - 객체 액세스

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.