方法区的内部结构
方法区存储什么?
《深入理解Java虚拟机》书中对方法区(Method Area)存储内容描述如下:它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。
类型信息
对每个加载的类型(类class、接口interface、枚举enum、注解annotation),JVM必须在方法区中存储以下类型信息:
- 这个类型的完整有效名称(全名=包名.类名);
- 这个类型直接父类的完整有效名(对于interface或是java.lang.Object,都没有父类);
- 这个类型的修饰符(public,abstract,final的某个子集);
- 这个类型直接接口的一个有序列表。
域(Field)信息
也就是我们常说的成员变量,域信息是比较官方的称呼。
- JVM必须在方法区中保存类型的所有域的相关信息以及域的声明顺序;
- 域的相关信息包括:域名称,域类型,域修饰符(public,private,protected,static,final,volatile,transient的某个子集)。
方法(Method)信息
JVM必须保存所有方法的以下信息,同域信息一样包括声明顺序:
- 方法名称;
- 方法的返回类型(包括 void 返回类型),void 在 Java 中对应的为 void.class;
- 方法参数的数量和类型(按顺序);
- 方法的修饰符(public,private,protected,static,final,synchronized,native,abstract的一个子集);
- 方法的字节码(byte codes)、操作数栈、局部变量表及大小(abstract和native方法除外);
- 异常表(abstract和native方法除外),异常表记录每个异常处理的开始位置、结束位置、代码处理在程序计数器中的偏移地址、被捕获的异常类的常量池索引。
举例说明
**
* 测试方法区的内部构成
*/
public class MethodInnerStructTest extends Object implements Comparable<String>,Serializable {
//属性
public int num = 10;
private static String str = "测试方法的内部结构";
//构造器
//方法
public void test1(){
int count = 20;
System.out.println("count = " + count);
}
public static int test2(int cal){
int result = 0;
try {
int value = 30;
result = value / cal;
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
@Override
public int compareTo(String o) {
return 0;
}
}
javap -v -p MethodInnerStructTest.class > test.txt
- 反编译字节码文件,并输出值文本文件中,便于查看。参数 -p 确保能查看 private 权限类型的字段或方法。
字节码指令:
Classfile /E:/Projects/JVM/out/production/com/heu/java/MethodInnerStructTest.class
Last modified 2021-3-7; size 1626 bytes
MD5 checksum 0d0fcb54854d4ce183063df985141ad0
Compiled from "MethodInnerStructTest.java"
//类型信息
public class com.heu.java.MethodInnerStructTest extends java.lang.Object implements java.lang.Comparable<java.lang.String>, java.io.Serializable
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #18.#52 // java/lang/Object."<init>":()V
#2 = Fieldref #17.#53 // com/heu/java/MethodInnerStructTest.num:I
#3 = Fieldref #54.#55 // java/lang/System.out:Ljava/io/PrintStream;
#4 = Class #56 // java/lang/StringBuilder
#5 = Methodref #4.#52 // java/lang/StringBuilder."<init>":()V
#6 = String #57 // count =
#7 = Methodref #4.#58 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#8 = Methodref #4.#59 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#9 = Methodref #4.#60 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#10 = Methodref #61.#62 // java/io/PrintStream.println:(Ljava/lang/String;)V
#11 = Class #63 // java/lang/Exception
#12 = Methodref #11.#64 // java/lang/Exception.printStackTrace:()V
#13 = Class #65 // java/lang/String
#14 = Methodref #17.#66 // com/heu/java/MethodInnerStructTest.compareTo:(Ljava/lang/String;)I
#15 = String #67 // 测试方法的内部结构
#16 = Fieldref #17.#68 // com/heu/java/MethodInnerStructTest.str:Ljava/lang/String;
#17 = Class #69 // com/heu/java/MethodInnerStructTest
#18 = Class #70 // java/lang/Object
#19 = Class #71 // java/lang/Comparable
#20 = Class #72 // java/io/Serializable
#21 = Utf8 num
#22 = Utf8 I
#23 = Utf8 str
#24 = Utf8 Ljava/lang/String;
#25 = Utf8 <init>
#26 = Utf8 ()V
#27 = Utf8 Code
#28 = Utf8 LineNumberTable
#29 = Utf8 LocalVariableTable
#30 = Utf8 this
#31 = Utf8 Lcom/heu/java/MethodInnerStructTest;
#32 = Utf8 test1
#33 = Utf8 count
#34 = Utf8 test2
#35 = Utf8 (I)I
#36 = Utf8 value
#37 = Utf8 e
#38 = Utf8 Ljava/lang/Exception;
#39 = Utf8 cal
#40 = Utf8 result
#41 = Utf8