Java를 공부하는 친구들은 Java가 처음부터 "한 번 작성하면 어디에서나 실행 가능"이라는 플랫폼 독립의 기치를 사용해 왔다는 것을 모두 알아야 합니다. 실제로 Java 플랫폼에는 또 다른 부적합성이 있는데 바로 언어 독립성입니다. . , 언어 독립성을 달성하려면 Java 시스템의 클래스 파일 구조 또는 실제로 Java에는 처음부터 두 가지 사양이 있었는데, 하나는 Java 언어 사양이고 다른 하나는 Java 가상 머신 사양입니다. Java 언어 및 규칙과 관련된 가상 머신 사양은 실제로 크로스 플랫폼 관점에서 설계되었습니다. 오늘 우리는 Java의 클래스 파일에 해당하는 바이트코드가 어떤 모습인지 알아보기 위해 실제적인 예를 들어보겠습니다. 본 글에서는 먼저 Class가 어떤 내용으로 구성되어 있는지 개괄적으로 설명하고, 실제 Java 클래스를 이용하여 클래스의 파일 구조를 분석해 본다.
계속하기 전에 먼저 다음 사항을 명확히 해야 합니다.
1) 클래스 파일은 8바이트 기반의 바이트 스트림으로 구성되며, 이러한 바이트 스트림은 지정된 순서로 엄격하게 배열되며, 8바이트를 초과하는 파일의 경우 데이터는 Big-Endian 순서로 저장됩니다. 즉, 상위 바이트는 하위 주소에 저장되고 하위 바이트는 상위 주소에 저장됩니다. 이는 크로스 플랫폼 클래스 파일의 핵심이기도 합니다. PowerPC 아키텍처는 Big-Endian 저장 순서를 사용하는 반면 x86 시리즈 프로세서는 Little-Endian 저장 순서를 사용하므로 클래스 파일이 각 프로세서 아키텍처에서 유지되도록 통합 저장소 순서대로 가상머신 사양이 통일되어야 합니다.
2) 클래스 파일 구조는 C 언어와 유사한 구조를 사용하여 데이터를 저장합니다. 데이터 항목에는 부호 없는 숫자와 테이블의 두 가지 주요 유형이 있습니다. 부호 없는 숫자는 u1, u2와 같은 숫자, 인덱스 참조 및 문자열을 표현하는 데 사용됩니다. , u4, u8은 각각 1바이트, 2바이트, 4바이트, 8바이트의 부호 없는 숫자를 나타내며, 테이블은 여러 개의 부호 없는 숫자와 기타 테이블로 구성된 복합 구조이다. 아마도 여기 있는 모든 사람들은 부호 없는 숫자와 테이블이 무엇인지 잘 알지 못할 것입니다. 그러나 아래 예제를 통해 설명하는 것은 중요하지 않습니다.
위의 두 가지 사항을 명확히 한 후 클래스 파일에서 엄격한 순서로 정렬된 바이트 스트림에 포함된 특정 데이터를 살펴보겠습니다.
위 그림을 보면 우리가 주목해야 할 것이 하나 있습니다. cp_info는 상수 풀을 의미하는데, 위 그림에서는 상수 풀을 상수 풀(constant_pool_co)로 표현하는데 사용됩니다. unt-1 상수는 여기서는 배열의 형태로 표현하는데, 모든 상수 풀의 상수 길이가 같다고 착각하지 마세요. 사실 이곳은 단지 설명의 편의를 위해 배열 방식을 사용하고 있지만, 프로그래밍 언어에서 int 유형의 배열은 각 int의 길이가 동일합니다. 이 점을 명확히 한 후, 위 그림의 각 항목이 구체적으로 무엇을 나타내는지 다시 살펴보겠습니다.
1) u4 매직은 매직넘버를 나타내며, 매직넘버는 4바이트를 차지합니다. 이는 실제로 파일 형식이 JPG 그림이나 AVI 동영상이 아닌 클래스 파일임을 의미합니다. Class 파일에 해당하는 매직넘버는 0xCAFEBABE입니다.
2) u2 major_version은 Class 파일의 마이너 버전 번호를 나타내며, 이 버전 번호는 u2 유형의 부호 없는 숫자 표현입니다.
3) u2 major_version은 Class 파일의 메이저 버전 번호를 나타내며, 메이저 버전 번호는 u2 타입의 부호 없는 숫자 표현이다. major_version 및 major_version은 현재 가상 머신이 클래스 파일의 현재 버전을 허용하는지 여부를 나타내는 데 주로 사용됩니다. 다양한 버전의 Java 컴파일러로 컴파일된 클래스 파일의 버전이 다릅니다. 상위 버전의 가상 머신은 하위 버전의 컴파일러에서 컴파일된 클래스 파일 구조를 지원합니다. 예를 들어 Java SE 6.0에 해당하는 가상 머신은 Java SE 5.0 컴파일러로 컴파일된 클래스 파일 구조를 지원하지만 그 반대는 지원하지 않습니다.
4) u2 Constant_pool_count는 상수 풀의 개수를 나타냅니다. 여기서는 상수 풀이 무엇인지에 초점을 맞춰야 합니다. 클래스 파일의 상수 풀은 주로 리터럴과 기호 참조를 저장합니다. 최종 상수의 값 또는 또는 특정 속성 등의 초기 값. 기호 참조는 주로 클래스 및 인터페이스의 정규화된 이름, 필드 이름 및 설명자, 메서드 이름 및 설명자를 저장합니다. 디스크립터의 개념에 대해서는 나중에 필드 테이블과 메소드 테이블을 논의할 때 다루겠습니다. 또한, Jvm의 메모리 모델은 힙, 스택, 메소드 영역, 프로그램 카운터로 구성되어 있다는 사실은 다들 알고 계시며, 메소드 영역에는 런타임 상수 풀이라는 영역이 있습니다. 실제로 런타임 상수 풀에 저장되어 있는 것들이죠. 컴파일러의 불멸성. 다양한 리터럴과 기호 참조가 있지만 런타임 상수 풀은 런타임에 다른 상수를 추가할 수 있습니다. 가장 대표적인 것은 String의 인턴 메서드입니다.
5) cp_info는 위에서 언급한 다양한 리터럴과 기호 참조를 포함하는 상수 풀을 나타냅니다. Java Virtual Machine Spec. Java SE 7 Edition의 상수 풀에는 총 14개의 데이터 항목이 있습니다. 각 상수는 테이블이며, 각 상수는 공통 부분 태그를 사용하여 해당 유형의 상수를 나타냅니다.
구체적인 세부 사항은 아래에 간략하게 설명되어 있으며 이후 예시에서 이를 구체화하겠습니다.
CONSTANT_Utf8_info 태그 플래그는 1, UTF-8 인코딩 문자열 CONSTANT_Integer_info 태그 플래그는 3, 정수 리터럴 CONSTANT_Float_info 태그 플래그는 4, 부동 소수점 리터럴 CONSTANT_Long_info 태그 플래그는 5, 긴 정수 리터럴 CONSTANT_Double_info 태그 플래그 비트는 6, 배정밀도 리터럴 CONSTANT_Class_info 태그 플래그는 7입니다. 클래스 또는 인터페이스의 기호 참조 CONSTANT_String_info 태그는 8, 문자열 유형의 리터럴 CONSTANT_Fieldref_info 태그는 9, CONSTANT_Methodref_info 태그 필드의 기호 참조는 10, 클래스 CONSTANT_InterfaceMethodref_info 태그에 있는 메소드의 기호 참조는 11, 기호 인터페이스 CONSTANT_NameAndType_info 태그의 메소드에 대한 참조 플래그 비트 12, 필드 및 메소드 이름, 유형에 대한 기호 참조
6) u2 access_flags는 다음 그림과 같이 클래스 또는 인터페이스의 액세스 정보를 나타냅니다.
7) u2 this_class는 클래스의 상수 풀 인덱스를 나타내며 상수 풀에 있는 CONSTANT_Class_info의 상수를 가리킵니다.
8) u2 super_class는 상수 풀에 있는 CONSTANT_Class_info의 상수를 가리키는 슈퍼 클래스의 인덱스를 나타냅니다.
9) u2 interface_counts는 인터페이스 수를 나타냅니다.
10) u2 인터페이스[인터페이스_카운트]는 인터페이스 테이블을 나타내며, 그 안의 각 항목은 상수 풀의 CONSTANT_Class_info 상수를 가리킵니다.
11) u2 fields_count는 클래스의 인스턴스 변수와 클래스 변수의 개수를 나타냅니다.
12) field_info fields[fields_count]는 필드 테이블의 정보를 나타내며, 필드 테이블의 구조는 다음과 같습니다.
위 그림에서 access_flags는 필드의 액세스 표현을 나타냅니다. 예를 들어 필드는 public, private 및 protected입니다. 등등, name_index는 필드 이름을 나타내며 상수 풀에 있는 CONSTANT_UTF8_info 유형의 상수를 가리키고, descriptor_index는 필드의 설명자를 나타내며 이는 또한 상수 풀에 있는 CONSTANT_UTF8_info 유형의 상수를 가리키며, attribute_count는 속성 테이블의 수를 나타냅니다. 필드 테이블 및 속성 테이블 필드, 메소드 및 클래스 속성을 설명하는 데 사용되는 확장 가능한 구조입니다. JVM(Java Virtual Machine)의 버전에 따라 지원되는 속성 테이블 수가 다릅니다.
13) u2methods_count는 메소드 테이블의 수를 나타냅니다.
14) method_info는 메소드 테이블을 나타냅니다. 메소드 테이블의 구체적인 구조는 아래 그림과 같습니다.
그 중 access_flags는 메소드의 액세스 표현을 나타내고, name_index는 이름의 인덱스를 나타내며, descriptor_index는 메소드의 디스크립터를 나타내며, attribute_count 및 attribute_info는 속성 테이블의 속성을 제외하고는 필드 테이블의 속성 테이블과 유사합니다. 필드 테이블과 메소드 테이블의 속성은 다릅니다. 예를 들어 메소드 테이블의 Code 속성은 메소드의 코드를 나타내지만 필드 테이블에는 Code 속성이 없습니다. 특정 클래스에 몇 개의 속성이 있는지는 나중에 클래스 파일 구조의 속성 테이블을 볼 때 논의할 것입니다.
15) attribute_count는 속성 테이블의 수를 나타냅니다. 속성 테이블에 관해서는 다음 사항을 명확히 해야 합니다.
속성 테이블은 클래스 파일 구조의 마지막, 즉 필드 테이블, 메소드 테이블 및 코드 속성에 존재합니다. 즉, 속성 테이블의 길이는 고정되어 있지 않습니다. 속성마다 길이가 다릅니다.
위의 Class 파일 구조에서 각 항목의 구성을 설명한 후, 실제적인 예를 들어 다음 내용을 설명합니다.
다음과 같이 코드 코드를 복사합니다 .
package com.ejushang.TestClass;
공개 클래스 TestClass는 Super{를 구현합니다.
개인 정적 최종 int staticVar = 0;
개인 int 인스턴스Var=0;
공개 int 인스턴스메소드(int param){
매개변수+1을 반환합니다.
}
}
인터페이스 슈퍼{ }
jdk1.6.0_37의 javac를 통해 컴파일된 TestClass.java에 해당하는 TestClass.class의 바이너리 구조는 아래 그림과 같습니다.
다음으로 앞서 언급한 Class의 파일 구조를 기반으로 위 그림의 바이트 스트림을 구문 분석하겠습니다.
1) 매직 넘버 <br/>클래스의 파일 구조를 보면 위 그림에서 처음 4바이트가 매직 넘버라는 것을 알 수 있습니다. 위 그림에서 주소 00000000h-00000003h의 내용이 매직 넘버입니다. Class 파일의 매직넘버는 0xCAFEBABE 입니다.
2) 메이저 및 마이너 버전 번호 <br/>다음 4바이트는 메이저 및 마이너 버전 번호입니다. 위 그림에서 00000004h~00000005h의 해당 번호는 0×0000이므로 Class의 Minor_version입니다. 는 0×0000이고 00000006h-00000007h의 해당 내용은 0×0032이므로 Class 파일의 major_version 버전은 0×0032입니다. 목표 매개변수.
3) 상수 풀의 개수 <br/>다음 2바이트는 00000008h부터 00000009h까지의 상수 풀 개수를 나타냅니다. 위 그림을 보면 그 값이 0×0018로 십진수로 24라는 것을 알 수 있습니다. 상수 풀의 개수를 명확히 할 필요가 있습니다. 상수 풀의 개수는 Constant_pool_count-1입니다. 1개 감소하는 이유는 인덱스 0은 클래스의 데이터 항목이 상수 풀의 상수를 참조하지 않음을 의미하기 때문입니다.
4) 상수 풀 <br/>위에서 상수 풀에는 다양한 유형의 상수가 있다고 말했습니다. TestClass.class의 첫 번째 상수를 살펴보겠습니다. 각 상수는 u1 유형 태그 식별자로 표시됩니다. 위 그림의 0000000ah에 있는 상수 유형 내용은 0x0A이고 보조 시스템으로 변환된 값은 10입니다. 위의 상수 유형 설명에서 태그 10이 붙은 상수는 Constant_Methodref_info이고 Constant_Methodref_info의 구조는 아래 그림과 같습니다.
그 중 class_index는 상수 풀에 있는 CONSTANT_Class_info 유형의 상수를 가리킨다. TestClass의 바이너리 파일 구조를 보면 class_index의 값이 0×0004(주소는 0000000bh-0000000ch)임을 알 수 있다. 네 번째 상수.
name_and_type_index는 상수 풀에 있는 CONSTANT_NameAndType_info 유형의 상수를 가리킵니다. 위 그림에서 알 수 있듯이 name_and_type_index의 값은 0×0013으로 상수 풀의 19번째 상수를 가리킨다.
다음으로 동일한 방법을 사용하여 상수 풀에 있는 모든 상수를 찾을 수 있습니다. 그러나 JDK는 상수 풀에 포함된 상수를 볼 수 있는 편리한 도구를 제공합니다. javap -verbose TestClass를 통해 상수 풀의 모든 상수를 가져올 수 있습니다. 스크린샷은 다음과 같습니다.
위 그림에서 TestClass의 상수 풀에 24개의 상수가 있음을 분명히 알 수 있습니다. 0번째 상수는 Class의 데이터 항목이 클래스의 어떤 상수도 참조하지 않음을 나타내는 데 사용되기 때문입니다. 일정한 풀. 위의 분석을 통해 TestClass의 첫 번째 상수 표현 방법은 class_index가 가리키는 네 번째 상수가 java/lang/Object이고, name_and_type_index가 가리키는 19번째 상수 값이 <init>:()V라는 것을 알 수 있습니다. 여기에서 메소드를 나타내는 첫 번째 상수는 Java 컴파일러에 의해 생성된 인스턴스 생성자 메소드를 나타냄을 알 수 있습니다. 상수 풀의 다른 상수도 같은 방식으로 분석할 수 있습니다. 자, 상수 풀을 분석한 후 다음으로 access_flags를 분석해 보겠습니다.
5) u2 access_flags는 클래스나 인터페이스에 대한 접근 정보를 나타낸다. 예를 들어 Class는 클래스인지 인터페이스인지, public인지, static인지, final인지 등을 나타낸다. 특정 액세스 플래그의 의미는 앞서 언급한 바 있습니다. TestClass의 액세스 플래그를 살펴보겠습니다. Class의 액세스 플래그는 0000010dh-0000010e이고 값은 0×0021입니다. 앞서 언급한 다양한 액세스 플래그의 플래그 비트에 따르면 다음과 같이 알 수 있습니다. 0×0021=0×0001|0×0020, 즉 ACC_PUBLIC 및 ACC_SUPER는 True이고, ACC_PUBLIC은 이해하기 쉽고, ACC_SUPER는 jdk1.2 이후에 컴파일된 클래스에 의해 전달되는 플래그입니다.
6) u2 this_class는 클래스의 인덱스 값을 나타내며, 클래스의 정규화된 이름을 나타내는 데 사용됩니다. 클래스의 인덱스 값은 아래 그림과 같습니다.
위 그림에서 알 수 있듯이 클래스 인덱스 값은 0×0003으로 상수 풀의 세 번째 상수에 해당한다. javap 결과를 통해 세 번째 상수가 CONSTANT_Class_info 타입의 상수임을 알 수 있다. 클래스의 전체 세부정보를 알 수 있는 정규화된 이름은 다음과 같습니다. com/ejushang/TestClass /TestClass
7) u2 super_class는 현재 클래스의 상위 클래스에 대한 인덱스 값을 나타내며, 해당 인덱스 값은 상수 풀에 있는 CONSTANT_Class_info 유형의 상수를 가리킨다. 그 값은 다음과 같다. 0×0004. 상수 풀의 첫 번째 4개 상수를 확인하면 TestClass의 상위 클래스의 정규화된 이름이 java/lang/Object임을 알 수 있습니다.
8)interfaces_count와interfaces[interfaces_count]는 인터페이스의 개수와 각 특정 인터페이스를 나타내며, TestClass의 인터페이스 개수와 인터페이스는 아래 그림과 같으며, 0×0001은 인터페이스 개수가 1개임을 의미하고, 0×은 인터페이스 개수를 의미합니다. 0005는 상수 풀 값의 인터페이스 인덱스를 의미하며 상수 풀에서 다섯 번째 상수를 찾습니다. 해당 유형은 CONSTANT_Class_info이고 값은 com/ejushang/TestClass/Super입니다.
9) fields_count 및 field_info , fields_count는 클래스의 field_info 테이블 수를 나타내고 field_info는 클래스의 인스턴스 변수 및 클래스 변수를 나타냅니다. 여기서 주의해야 할 점은 field_info는 상위 클래스에서 상속된 필드의 구조입니다. field_info는 아래 그림과 같습니다.
그 중 access_flags는 public, private, protected, static, final 등 해당 필드의 액세스 플래그를 나타냅니다. access_flags의 값은 아래 그림과 같습니다.
그 중 name_index와 descriptor_index는 모두 상수 풀의 인덱스 값으로 각각 필드의 이름과 필드의 디스크립터를 나타냅니다. 필드 이름은 이해하기 쉽지만, 해당 필드의 디스크립터를 이해하는 방법은 다음과 같습니다. 필드? 실제로 JVM 사양에서는 필드 설명자가 다음 그림과 같이 지정됩니다.
그 중 위 그림의 마지막 줄에 주목해야 합니다. 이는 1차원 배열의 설명자를 나타냅니다. String[][]에 대한 설명자는 [[ Ljava/lang/String입니다. int[][] 기호는 [[I입니다. 다음 attribute_count 및 attribute_info는 각각 속성 테이블 및 속성 테이블의 수를 나타냅니다. 위의 TestClass를 예로 들어 TestClass의 필드 테이블을 살펴보겠습니다.
먼저, TestClass의 필드 수를 살펴보겠습니다. 아래 그림과 같습니다.
위 그림에서 볼 수 있듯이 TestClass에는 두 개의 필드가 있습니다. TestClass의 소스 코드를 보면 실제로 두 개의 필드만 있음을 알 수 있습니다. 다음으로 첫 번째 필드를 살펴보겠습니다. private int staticVar, 클래스 파일의 이진 표현은 아래와 같습니다.
그 중 0x001A는 access_flags 테이블을 보면 ACC_PRIVATE, ACC_STATIC, ACC_FINAL임을 알 수 있습니다. 다음으로 0×0006과 0×0007은 각각 상수 풀의 6번째 상수를 나타냅니다. 상수 풀을 보면 해당 값이 staticVar 및 I라는 것을 알 수 있습니다. 여기서 staticVar는 필드 이름이고 I는 필드 설명자입니다. 위의 디스크립터 설명을 통해 설명하는 것은 int형 변수이고, 다음으로 0×0001은 staticVar 필드 테이블의 속성 테이블 개수를 의미하며, 이에 해당하는 속성 테이블이 1개 있음을 알 수 있다. staticVar 필드에 0×0008은 상수 풀의 8번째 상수를 나타냅니다. 상수 풀을 보면 이 속성이 ConstantValue 속성이고 ConstantValue 속성의 형식은 아래 그림과 같습니다.
그 중 attribute_name_index는 속성 이름의 상수 풀 인덱스를 나타냅니다. 이 예에서는 ConstantValue의 attribute_length가 2로 고정되어 있으며, 이 예에서는 ConstantValue_index가 0입니다. ×0009. 9번째 상수를 볼 수 있습니다. 값이 0인 CONSTANT_Integer_info 유형의 상수를 나타냅니다.
private static final int staticVar=0이라고 말한 후, TestClass의 private int instanceVar=0에 대해 이야기해 보겠습니다. 이 예에서 instanceVar의 이진 표현은 아래 그림과 같습니다.
그 중 0×0002는 액세스 표시가 ACC_PRIVATE임을 의미하고, 0x000A는 필드 이름을 의미하며 상수 풀의 10번째 상수를 보면 필드 이름이 instanceVar임을 알 수 있으며, 0× 0007은 상수 풀의 7번째 상수를 가리키는 필드의 디스크립터를 의미하며, 상수 풀을 보면 7번째 상수가 I라는 것을 알 수 있는데, 이는 마지막으로 0×0000이 인스턴스Var의 타입을 의미한다는 것을 의미합니다. 속성 테이블의 개수는 0입니다. .
10)methods_count 및methods_info , 여기서methods_count는 메소드 수를 나타내고,methods_info는 메소드 테이블을 나타내며, 메소드 테이블의 구조는 아래 그림과 같습니다.
위 그림에서 볼 수 있듯이 method_info와 field_info의 구조는 메소드 테이블의 모든 플래그 비트와 access_flag 값이 아래 그림과 같습니다.
그 중 name_index와 descriptor_index는 메소드의 이름과 디스크립터를 나타내며, 각각 상수 풀을 가리키는 인덱스이다. 여기서는 메서드 설명자를 설명해야 합니다. 메서드 설명자의 구조는 다음과 같습니다. (매개변수 목록) 반환 값 예를 들어 public int instanceMethod(int param)의 설명자는 다음과 같습니다. (I) 이는 int를 가짐을 의미합니다. 그리고 반환 값도 int 유형의 메소드입니다. 다음은 속성 수와 속성 테이블입니다. 메소드 테이블과 필드 테이블 모두 속성 수와 속성 테이블을 가지고 있지만, 포함된 속성은 다음과 같습니다. 다른. 다음으로 TestClass를 사용하여 메서드 테이블의 이진 표현을 살펴보겠습니다. 먼저, 메소드 테이블의 수를 살펴보겠습니다. 스크린샷은 다음과 같습니다.
위 그림에서 볼 수 있듯이 메소드 테이블의 개수는 0×0002로 두 개의 메소드가 있음을 의미한다. 다음으로 첫 번째 메소드를 분석해 보자. 먼저 TestClass의 첫 번째 메소드의 access_flag, name_index, descriptor_index를 살펴보자. 스크린샷은 다음과 같습니다.
위 그림에서 access_flags가 0x0001임을 알 수 있습니다. 위의 access_flags 플래그 설명에서 해당 메서드의 access_flags 값이 ACC_PUBLIC이고, name_index가 0x000B임을 알 수 있습니다. 11번째 상수는 메소드 이름이 <init>인 것을 알면, 0x000C는 descriptor_index가 상수 풀의 12번째 상수를 뜻하고, 그 값이 ()V라는 뜻인데, 이는 <init> 메소드에 매개변수와 반환값이 없다는 뜻이다. 실제로 이것은 컴파일러가 자동으로 생성한 인스턴스 생성자 메서드입니다. 다음 0×0001은 <init> 메소드의 메소드 테이블에 1개의 속성이 있음을 나타냅니다. 속성 스크린샷은 다음과 같습니다.
위 그림에서 볼 수 있듯이 0x000D에 해당하는 상수 풀의 상수는 메소드의 Code 속성을 나타내는 Code입니다. 따라서 여기서는 메소드의 코드가 속성의 Code 속성에 저장된다는 점을 모두가 이해해야 합니다. 클래스 파일의 메소드 테이블에 있는 테이블입니다. 다음으로 Code 속성을 분석합니다. Code 속성의 구조는 아래 그림과 같습니다.
그 중 attribute_name_index는 상수 풀에서 값이 Code인 상수를 가리키며, attribute_length의 길이는 Code 속성 테이블의 길이를 나타낸다. (길이에는 attribute_name_index와 attribute_length의 6바이트 길이가 포함되지 않는다는 점에 유의해야 한다) ).
max_stack은 최대 스택 깊이를 나타내며, 가상 머신은 런타임 시 이 값을 기준으로 스택 프레임의 피연산자 깊이를 할당하고, max_locals는 로컬 변수 테이블의 저장 공간을 나타냅니다.
max_locals의 단위는 가상 머신이 로컬 변수에 대한 메모리를 할당하는 최소 단위인 슬롯이다. 런타임 시 byte, char, int 등 32비트 유형을 초과하지 않는 데이터 유형은 1을 차지한다. 슬롯, 더블 및 롱 64비트 데이터 유형은 2개의 슬롯을 할당해야 합니다. 또한, max_locals의 값은 모든 지역 변수에 필요한 메모리의 합이 아닙니다. 지역 변수가 해당 범위를 초과하면 슬롯이 재사용될 수 있기 때문입니다. 점유된 슬롯은 재사용됩니다.
code_length는 바이트코드 명령어의 수를 나타내고, code는 바이트코드 명령어를 나타냅니다. 위 그림에서 코드 유형이 u1이라는 것을 알 수 있으며, u1 유형의 값은 0×00-0xFF이고 해당 십진수는 0-입니다. 255. 현재 가상 머신 사양에는 200개 이상의 명령어가 정의되어 있습니다.
예외_테이블_길이와 예외_테이블은 각각 해당 메소드에 해당하는 예외 정보를 나타낸다.
attribute_count와 attribute_info는 각각 Code 속성의 속성 수와 속성 테이블을 나타냅니다. 여기서 속성 테이블은 클래스 파일, 메소드 테이블, 필드에 매우 유연하게 존재할 수 있음을 알 수 있습니다. 테이블 및 코드 속성.
다음으로, 위의 init 메소드의 Code 속성 스크린샷을 보면, 속성 테이블의 길이는 0×00000026, max_stack의 값은 0×0002, 값은 알 수 있습니다. max_locals의 길이는 0× 0001이고, code_length의 길이는 0x0000000A, 그 다음에는 00000149h입니다. 00000152h는 바이트코드입니다. 다음으로,Exception_table_length의 길이는 0×0000이고, attribute_count의 값은 0×0001입니다. 상수 풀에 있는 속성의 이름을 나타내는 00000158h입니다. 14번째 값을 얻으려면 상수의 값은 LineNumberTable, LineNu입니다. mberTable은 Java 소스 코드 줄 번호와 바이트코드 줄 번호 간의 대응을 설명하는 데 사용됩니다. 이는 런타임 시 필수 속성이 아닙니다. -g:none 컴파일러 매개변수를 통해 이 정보 생성을 취소하면 가장 큰 영향을 받게 됩니다. be 예외가 발생하면 스택에 오류 라인 번호가 표시되지 않으며 디버깅 중에 소스 코드에 따라 중단점을 설정할 수 없습니다. 다음으로 LineNumberTable의 구조를 아래와 같이 살펴보겠습니다.
그 중 attribute_name_index는 위에서 언급한 것으로 상수 풀의 인덱스를 나타내고, attribute_length는 속성 길이를 나타내며, start_pc와 line_number 테이블은 바이트코드의 라인 번호와 소스 코드의 라인 번호를 나타낸다. 이 예에서 LineNumberTable 속성의 바이트 스트림은 다음과 같습니다.
위의 TestClass의 첫 번째 메서드를 분석한 후 동일한 방식으로 TestClass의 두 번째 메서드를 분석할 수 있습니다.
그 중 access_flags는 0×0001, name_index는 0x000F, descriptor_index는 0×0010이다. 상수 풀을 보면 이 메소드가 public int instanceMethod(int param) 메소드임을 알 수 있다. 위와 비슷한 방법을 통해, instanceMethod의 Code 속성이 아래 그림과 같다는 것을 알 수 있습니다.
마지막으로 Class 파일의 속성을 분석해 보겠습니다. 00000191h~00000199h는 Class 파일의 속성 테이블입니다. 여기서 0×0011은 속성 이름을 나타냅니다. 상수 풀을 보면 속성 이름이 SourceFile이라는 것을 알 수 있습니다. 그림과 같이 SourceFile의 구조를 살펴보겠습니다.
그 중 attribute_length는 속성의 길이이고, sourcefile_index는 값이 소스 코드 파일 이름인 상수 풀의 상수를 가리킵니다. 이 예에서 SourceFile 속성의 스크린샷은 다음과 같습니다.
그 중 attribute_length는 0×00000002로 길이가 2바이트라는 뜻이고, sourcefile_index의 값은 0×0012이다. 상수 풀의 18번째 상수를 보면 소스코드 파일명이 TestClass라는 것을 알 수 있다. .자바
마지막으로 기술에 관심이 있는 친구들이 더 많이 소통할 수 있었으면 좋겠습니다. 개인 웨이보: (http://weibo.com/xmuzyq)