`

深入理解Java虚拟机读书笔记之执行子系统

阅读更多

一、Class类结构:

class文件是以8位字节为基础单位的二进制流。

ClassFile {
u4 magic;//魔数(0xCAFEBABE。固定值)
u2 minor_version;//次版本号
u2 major_version;//主版本号
u2 constant_pool_count;//常量池容量计数值
cp_info constant_pool[constant_pool_count-1];//常量池
u2 access_flags;//访问标志
u2 this_class;//类索引
u2 super_class;//父类索引
u2 interfaces_count;//接口计数器
u2 interfaces[interfaces_count];//接口索引集合
u2 fields_count;//字段计数器
field_info fields[fields_count];//字段表
u2 methods_count;//方法计数器
method_info methods[methods_count];//方法表
u2 attributes_count;//属性表计数器
attribute_info attributes[attributes_count];//属性表集合
}
常量池的项目类型如下(每一种类型的可以看作一种数据结构):

 Class_info型的结构如下:
类型 名称 数量
u1(占用一个字节) tag=7 1
u2(占用两个字节) name_index(指向常量池中utf8_info类型的常量) 1
utf8_info类型的结构如下:
类型 名称 数量
u1 tag=1 1
u2 length(长度) 1
u1 bytes lenth
例如如果存储“java.lang.String”字符串,那么length=16,bytes为UNICODE编码(具体说是UTF-16编码)的。
可以使用javap命令分析class文件字节码:到class文件所在的文件夹,然后运行javap -verbose xxxxx(这个是类名)
javac在编译的时候把this关键字作为一个普通的方法参数的访问,然后虚拟机在调用实例的时候自动传入此参数。
 
LineNumberTable属性用于描述java源文件行号和字节码行号的对于关系,调试可以对应起来行号。LocalVariableTable属性记录局部变量表之间的变量和源码中定义的变量之间的关系,这样在调试的时候可以对应起来变量,另外才可以通过程序得到入参的名字。
对于泛型虽然运行时进行了类型擦除,但是通过Class元数据依然可以获得泛型的信息是因为LocalVariableTypeTable.
二、虚拟机类加载机制
java类加载的时机:1、遇到new /putstatic /getstatic/invokestatic指令 2、java.lang.Class反射调用3、父类加载4、main方法第一个加载。
 
类加载的过程:
1、加载:获得二进制流、在方法区转化为运行时结构、在堆中生成java.lang.Class对象
2、校验:校验二级制流、校验类。。。
3、准备:为类变量在方法区分配内存空间
4、解析:实际上也是校验的过程。把符号引用解析为直接引用的过程。
5、初始化:clinit方法,并调用static代码。在初始化的工程中会加锁与同步,如果static块中很耗时,可能会造成线程阻塞。
 
java会对数组类型创建一个类,会有length和clone方法。
类加载器:
启动类加载器:加载<JAVA_HOME>\lib目录下或者被-Xbootclasspath参数指定的路径,并且被虚拟机识别的
扩展类加载器:加载<JAVA_HOME>\lib\ext目录中,或者被java.ext.dirs系统变量指定的类库。父加载器是启动类加载器。
应用程序类加载器:有sun.misc.Launcher$AppClassLoader实现,加载classPath自动的类库,父加载器是扩展类加载器。是ClassLoader。getSystemClassLoader()的返回值。
 
三、虚拟机字节码执行引擎
1、运行时栈的结构:包括局部变量表。局部变量表中的Slot是可以重用的。操作数栈:编译器最大操作数栈已经确定。动态链接:包含指向运行时常量池中该栈帧所属方法的引用。方法返回地址。
2、方法调用:A.解析调用是一个静态的工程,属于编译器可知。
B、静态分派:重载的运用,重载的时候是通过参数的静态类型而不是实际类型作为判断依据的。发生在编译阶段。
C:动态分派:重写的运用。会在运行态决定执行的方法。首先查找本类的方法,如果找不到就查找父类。由于动态分派是什么频繁的过程,虚拟机会为类中创建一个虚方法表,来代替元数据查找提高性能。一般在初始化阶段把类的方法表也初始化。

 虚方法表中存放着各个方法的入口,如果子类没有重写,那么子类和父类的方法入口是一样的,如果重写了,子类方法表的地址将会替换为指向子类实现版本的入口地址.
基于栈的解释执行引擎:
解释执行:通过解释器执行,基于操作数栈(可移植性好)
编译执行:通过即时编译器产生本地代码执行,本地代码会放在方法区。
  • 大小: 74.5 KB
  • 大小: 70.9 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics