>  기사  >  Java  >  JVM 클래스 로딩 메커니즘에 대한 자세한 소개(코드 예)

JVM 클래스 로딩 메커니즘에 대한 자세한 소개(코드 예)

不言
不言원래의
2018-09-25 15:14:542151검색

이 기사는 JVM 클래스 로딩 메커니즘에 대한 자세한 소개(코드 예제)를 제공합니다. 이는 특정 참조 가치가 있으므로 도움이 될 수 있습니다.

1. 개요

Java는 C/C++와 같은 전통적인 컴파일 언어와도 다르며, PHP와 같은 동적 스크립트 언어와도 다릅니다. Java는 반컴파일된 언어라고 할 수 있습니다. 우리가 작성하는 클래스는 먼저 .class 파일로 컴파일됩니다. 그런 다음 이 클래스를 사용하면 이 클래스에 해당하는 .class 파일이 메모리에 로드됩니다. 이 .class의 내용은 Jvm 클래스 로딩 메커니즘을 통해 메모리에 로드됩니다.

가상머신은 클래스를 기술하는 데이터를 클래스 파일에서 메모리로 로딩하고, 데이터를 검증하고, 변환, 파싱, 초기화를 거쳐 최종적으로 가상머신에서 직접 사용할 수 있는 자바 타입을 형성하는 것입니다. 가상 머신의 클래스 로딩 메커니즘.

2. 클래스 로딩의 다양한 단계

Loading

로딩 과정 중 "클래스 로딩" 프로세스의 첫 번째 단계에서는 가상 머신이 다음 세 가지를 완료해야 합니다

  1. 클래스 전달 이 클래스를 정의하는 이진 바이트 스트림의 정규화된 이름입니다.

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

  3. 메서드 영역에서 이 클래스의 다양한 데이터에 대한 액세스 항목 역할을 하는 메모리에서 이 클래스를 나타내는 java.lang.Class 객체를 생성합니다.

시스템에서 제공하는 부트 클래스 로더나 상대적으로 무료인 사용자 정의 클래스 로더를 사용하여 로딩 단계를 완료할 수 있다는 점은 언급할 가치가 있지만 어레이의 경우에는 그렇지 않습니다, 배열 클래스 자체는 클래스 로딩을 통해 생성되지 않고 Java 가상 머신에서 직접 생성됩니다. 하지만 데이터가 저장되는 요소 유형은 클래스 로더에서 생성해야 합니다.

로딩 단계와 다음 단계의 연결 부분이 인터리브되지만, 로딩 단계와 연결 단계의 시작 시간은 여전히 ​​고정된 순서를 유지합니다.

확인

확인은 연결 단계의 첫 번째 단계입니다. 이 단계의 목적은 클래스 파일의 바이트 스트림에 포함된 정보가 현재 가상 머신의 요구 사항을 충족하고 가상 머신 자체의 보안. 범위를 벗어난 배열 및 객체의 무작위 변환과 같은 작업은 컴파일러에 의해 거부되지만 .class 파일은 반드시 Java 소스 코드에서 컴파일될 필요는 없으며 다른 방법으로 생성될 수 있습니다. .class 파일을 확인해야 합니다.

검증 단계의 중요성은 자명합니다. 이 단계의 엄격한 여부는 Java 가상 머신이 악성 코드 공격을 견딜 수 있는지 여부를 직접적으로 결정합니다. 실행 성능 측면에서 검증 단계의 작업량은 가상에 있습니다. 기계는 클래스 로딩 시스템의 상당 부분을 차지합니다.

전체적으로 검증 단계는 파일 형식 검증, 메타데이터 검증, 바이트코드 검증, 기호 참조 검증의 4가지 검증 작업 부분으로 대략 나눌 수 있습니다.

  • 기호 확인: 주요 목적은 입력 바이트 스트림이 올바르게 구문 분석되어 메소드 영역에 저장될 수 있는지, 형식이 Java 유형 정보를 설명하기 위한 요구 사항을 충족하는지 확인하는 것입니다. 이 부분은 바이너리 스트림 검증을 기반으로 하며, 이는 메모리에 로드되고 후속 검증은 메모리에서 수행됩니다.

  • 메타데이터 검증: 이 검증은 주로 클래스의 메타데이터 정보에 대한 의미론적 검증을 수행하여 Java 언어 사양을 따르지 않는 메타데이터 정보가 없는지 확인합니다.

  • 바이트코드 검증: 이 부분은 검증 단계 중 가장 복잡한 단계입니다. 주요 목적은 데이터 흐름 및 제어 흐름 분석을 통해 프로그램이 합법적이고 논리적인지 확인하는 것입니다.

  • 기호 참조 확인: 가상 머신이 기호 참조를 직접 참조로 변환할 때 기호 참조가 발생하므로 구문 분석 작업이 정상적으로 실행될 수 있습니다.

Preparation

준비 단계는 형식적인 클래스 변수(정적 변수)에 대해 메모리를 할당하고 클래스 변수의 초기 값을 설정하는 단계입니다. 이러한 변수가 사용하는 메모리는 메소드에 할당됩니다. 영역. 이때는 인스턴스 변수가 아닌 클래스 변수(정적 변수)만 할당된다는 점을 언급할 가치가 있습니다.

일반적으로 클래스 변수의 초기값을 설정합니다. 이 초기값은 int 유형의 경우 0과 같은 데이터 유형의 기본값을 나타냅니다. 그러나 클래스 변수가 final에 의해 수정되면 상황이 달라지며, 이 경우 주어진 값이 직접 할당됩니다.

Parsing

파싱 단계는 가상 머신이 상수 풀의 기호 참조를 직접 참조로 바꾸는 프로세스입니다. 여기서는 상징적 참조가 무엇인지, 직접 참조가 무엇인지에 대해 설명합니다.

기호 참조: 기호 참조는 참조된 대상을 설명하기 위해 일련의 기호를 사용합니다. 기호는 사용 시 대상을 명확하게 찾을 수 있는 한 모든 형태의 리터럴이 될 수 있습니다.

직접 참조: 직접 참조는 대상에 대한 포인터, 상대 오프셋 또는 대상을 간접적으로 찾을 수 있는 핸들일 수 있습니다.

파싱 작업은 주로 클래스 또는 인터페이스, 필드, 클래스 메서드, 인터페이스 메서드, 메서드 유형, 메서드 핸들 및 호출 사이트 한정자 등 7가지 유형의 기호 참조에서 수행됩니다.

초기화

클래스 초기화 단계는 클래스 로딩 프로세스의 마지막 단계입니다. 로딩 단계에서 사용자 애플리케이션이 사용자 정의 클래스 로더를 통해 참여할 수 있다는 점을 제외하고 나머지 작업은 가상 머신에 의해 완전히 지배되고 제어됩니다. . 초기화 단계에서는 클래스에 정의된 Java 코드가 실제로 실행되기 시작합니다.

준비 단계에서는 변수에 시스템이 요구하는 초기값을 할당하고, 초기화 단계에서는 프로그래머가 프로그램을 통해 작성한 계획 영역에 따라 클래스 변수 및 기타 리소스를 초기화합니다.

3. 흥미로운 코드 조각

public class StaticTest
 {

     public static void main(String[] args)
     {
         staticFunction();
     }
  
     static StaticTest st = new StaticTest();
  
     static
     {
         System.out.println("1");
     }
  
     {
         System.out.println("2");
     }
  
     StaticTest()
     {
         System.out.println("3");
         System.out.println("a="+a+",b="+b);
     }
  
     public static void staticFunction(){
         System.out.println("4");
     }
  
     int a=110;
     static int b =112;
 }

이 코드를 실행한 결과는 무엇인가요?

답은:

2
3
a=110,b=0
1
4

이게 왜일까요? 다음 사항에 대해 생각해 보세요.

이 코드를 이해하려면 Java의 클래스 로딩 메커니즘뿐만 아니라 초기화 단계도 이해해야 합니다. 정적 코드 블록 및 정적 멤버 변수의 초기화는 코드 순서와 관련이 있습니다.

클래스 로딩 과정은 로딩->연결(검증, 준비, 파싱)->초기화 순입니다.

1. 준비 단계에서는 클래스 변수에 기본값이 설정되므로 다음과 같은 경우: st=null, b=0,

2 초기화 단계에서는 클래스 생성자가 먼저 실행됩니다.

즉, 정적 수정 코드 블록을 실행하고 정적 수정 변수에 값을 할당하는 것뿐입니다. 정적 수정 코드 블록 및 클래스 변수의 실행 순서는 파일에 나타나는 순서를 기반으로 합니다. 그리고 static StaticTest st = new StaticTest() 가 먼저 실행되므로 객체를 초기화하는 new StaticTest() 가 실행됩니다

2.1 객체의 초기화 과정에서 멤버 변수(코드 블록)가 실행됩니다. 그런 다음 생성자 메서드를 실행합니다. 멤버 변수의 실행 순서도 먼저 선언한 사람이 먼저 실행하므로 첫 번째 코드 블록

2.2 멤버 변수가 실행된 후 생성자 메서드가 실행됩니다. time, a=110, b=0 ;

3. static StaticTest st = new StaticTest(); 에 의해 트리거된 비정적 코드의 초기화 프로세스는 여기서 끝나고 정적 코드의 초기화가 계속되므로 1이 출력됩니다.

4. 여기서 전체 클래스 로딩이 끝나고 코드가 실행되어 4가 출력됩니다.

다음을 보세요

public class StaticTest
 {

     public static void main(String[] args)
     {
         staticFunction();
     }
  
  
     static
     {
         System.out.println("1");
     }
  
     {
         System.out.println("2");
     }
  
     StaticTest()
     {
         System.out.println("3");
         System.out.println("a="+a+",b="+b);
     }
  
     public static void staticFunction(){
         System.out.println("4");
     }
  
     int a=110;
     static int b =112;
     static StaticTest st = new StaticTest();  //将这条语句放到最下面
 }

구문 하나만 변경하면 이 코드를 실행한 결과는

1
2
3
a=110,b=112
4
입니다.

위 내용은 JVM 클래스 로딩 메커니즘에 대한 자세한 소개(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

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