深入Java虚拟机读书笔记[6:7]

第六章 Java class文件

这章的内容讲的是编译后的class文件格式,我根据内容写了个class文件解析程序。 https://github.com/JohnWong/class-file-parser

第七章 类型的生命周期

1. Java虚拟机通过装载、连接与初始化一个Java类型

连接步骤包括验证、准备、解析(可选)。在类和接口被装载和连接的时机上,Java虚拟机规范给实现提供了一定的灵活性。但是要求每个类或者接口必须在首次主动使用时初始化。主动使用包括:

a) 创建某个类的实例。
b) 调用某个类的静态方法。
c) 使用某个类或接口的静态字段,或者对其赋值。final修饰的静态字段除外。
d) 调用Java API中的某些反射方法。
e) 初始化某个类的子类。
f) 虚拟机启动某个被标明为启动类的类。

2. 装载

a) 通过该类型的全限定名产生一个代表该类型的二进制数据流 b) 解析这个二进制数据流为方法区内的内部数据结构 c) 创建一个表示该类型的java.lang.Class类的实例

类装载器并不需要一直等到某个类型首次主动使用时再去装入他。Java虚拟机规范允许类装载器缓存 Java类型的二进制表现形式。如果预先装载时遇到问题,应该在首次主动使用时报告该问题。

3. 验证

连接过程的第一步,确认类型符合Java语言的语义并且不会危害虚拟机的完整性。不同虚拟机验证有一些灵活性,可以决定如何以及何时验证类型。除Object外所有类都有超类和class文件格式检查发生在装载期间,但是逻辑上属于验证。检查被装载的类型是否有任何问题的整个过程都属于验证。符号引用验证属于验证,但是往往在解析的时候发生,是连接的第三步。正式验证阶段执行之前未进行的和之后不会进行的检查。包括:

a) 类之间二进制兼容性检查:final不能有子类、final方法不能被覆盖、类型和超类型之间无不兼容的方法声明。
b) 类与所有超类之间互相二进制兼容:常量池入口互相之间一致、常量池中所有特殊字符串是否符合格式、字节码完整性。

虚拟机的实现没有强求在正式的连接验证阶段进行字节码验证,但是连接过程中一次性验证字节码流而非在程序执行时动态验证,使得Java程序运行速度得到很大提高。

4. 准备

连接过程的第二步,为类变量分配内存,设置默认初始值。但在初始化阶段之前,类变量都没有被初始化为真正的初始值(不执行Java代码)。也可能为一些数据结构分配内存,目的是提高程序的性能。例如方法表,包含指向类中每一个方法的指针,使得继承方法执行时不需要搜索超类。

5. 初始化

一个变量的初始值通过类变量初始化语句或者静态初始化语句给出。这些被Java编译器收集在一起,放到类/接口初始化方法中。在class文件中为<clinit>。只能由拟机调用。

初始化一个类的步骤:

a) 如果类存在直接超类且未被初始化,则初始化直接超类。
b) 如果类存在一个类初始化方法,就执行此方法。

使用一个非常量静态字段只有当类或者接口的确声明了这个字段时才主动使用。如果一个字段既是static又是final的,并且使用一个编译时常量表达式初始化,就不是对声明该字段的类的主动使用。

6. 对象的声明周期

类实例化方法:

a) new
b) Class或者java.lang.reflect.Constructor对象的newInstance方法
c) 现有对象的clone方法
d) java.io.ObjectInputStream类的readObject方法反序列化

还有几种情况会隐含地实例化:

a) 每个命令行参数中都会有String对象,组织成String数组传递给main方法
b) 对于Java虚拟机中装载的每一个类都会暗中实例化一个Class对象来代表这个类型
c) Java虚拟机装载常量池中的包含CONSTANTString info入口的类的时候,会创建新的String对象的实例来表示这些常量字符串。把方法区的CONSTANTString info入口转换成一个堆中的String实例的过程是常量解析过程的一部分。
d) 使用字符串连接操作符会在计算表达式的过程中创建String和StringBuffer对象。

类实例初始化方法为<init>,如果没有构造方法,会默认创建一个无参构造方法,并调用父类的无参构造方法。

7. finalize()方法会在垃圾收集器释放这个实例所占据的内存空间之前执行。如果终结方法代码执行后,对象重新被引用了,随后再次变得不被引用,垃圾收集器不会第二次调用终结方法。

8. 卸载类型

使用启动类装载器装载的类型永远不会被卸载。只有用户定义的类装载器装载的类型才会变得不可触及,被虚拟机回收。判断是否可以触及:a) 如果程序保持对Class实例的明确引用;b) 在堆中存在一个可触及的对象,在方法区中它的类型数据指向一个Class实例。

时间: 2024-12-02 19:15:00

深入Java虚拟机读书笔记[6:7]的相关文章

深入Java虚拟机读书笔记[8:9]

第八章 连接模型 1. 动态连接和解析 每个类或者接口都编译为独立的class文件,他们之间通过接口(Harbor)符号相互联系,或者与Java API class文件相联系.class文件把所有引用符号保存在常量池,每一个class文件有一个常量池,被装载的类或者接口有一份内部版本的运行时常量池.常量池解析:根据符号查找到试题,把符号替换成直接引用.JDBC通常用forName装载时因为传递第三个参数为true时可以确保类被初始化,静态初始化方法会在DriverManger中被注册驱动程序.

深入Java虚拟机读书笔记[10:20]

第十章 栈和局部变量操作 第十一章 类型转换 第十二章 整数运算 第十三章 逻辑运算 第十四章 浮点运算 第十五章 对象和数组 第十六章 控制流 第十七章 异常 以上一些是操作码相关的内容, 第十八章 finally子句 微型子例程 字节码中的finally子句表现的很像微型子例程.Java方法与微型子例程使用不同的指令集.跳转到微型子例程的指令是jsr或者jsr_w,将返回地址压入栈.执行完毕后调用ret指令.ret指令并不会从栈中弹出返回地址,而是在子例程开始的时候将返回地址从栈顶取出存储在

深入Java虚拟机读书笔记[5]

第五章 Java虚拟机 1. Java虚拟机内部体系结构 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配.当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用. 堆内存用来存放由new创建的对象和数组.在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理. 2. 数据类型 Java虚拟机中的数据类型分为基本类型和引用类型.Java语言中的所有基本类型同样为

深入Java虚拟机读书笔记[1:4]

第一章 Java体系结构 1. Java体系结构 the Java programming language the Java class file format the Java Application Programming Interface the Java Virtual Machine 2. Java语言优点或使用的技术: object-orientation multi-threading structured error-handling garbage collection d

《深入Java虚拟机》笔记:指令集 (转)

<深入Java虚拟机>笔记:指令集   指令 含义 iconst_m1 把int型常量-1压入栈中 iconst_0 把int型常量压入栈中 fconst_1 把float型常量1压入栈中 lconst_2 把long型常量2压入栈中 dconst_3 把double型常量3压入栈中 bipush byte1 把byte1转换成int型压入栈中 sipush byte1,byte2 把byte1,byte2组成的short转换成int压入栈中 aconst_null 把空对象压入栈中 ldc

java虚拟机学习笔记

笔记 1.编译顺序:                 编译器                     虚拟机      虚拟机          java源文件*.java------->字节码*.class------>类装载器--->执行引擎 一个.class文件只能包含一个类或接口.因此.java文件中定义了多少类,编译时就会生成多少.class文件(内部类不算). 2.java程序可以选择两种方式访问底层系统,由程序员选择:(1).通过java程序调用javaapi调用本地方法,

java虚拟机学习笔记2

笔记 11.数组数组也是类的对象.具有相同类型和维数的数组属于同一个类(不管长度只看维数).数组的长度属于对象实例.多维数组也是一维数组.如二 维数组,即为一个一维数组,该一维数组的每个元素是一个数组的引用.数组和普通对象一样也存储在堆中.数组名为数组的引用,通过索引即数组标号来访问数组内容. 12.异常在java栈帧的帧数据区内保存有针对该方法的异常表的引用.异常表记载了该方法的字节码(*.class)受catch子句保护的范围(即try子句里的 字节码).当某个方法抛出异常时,虚拟机在对应的

java虚拟机学习笔记1

笔记 1.编译顺序:                 编译器                     虚拟机      虚拟机          java源文件*.java------->字节码*.class------>类装载器--->执行引擎 一个.class文件只能包含一个类或接口.因此.java文件中定义了多少类,编译时就会生成多少.class文件(内部类不算). 2.java程序可以选择两种方式访问底层系统,由程序员选择:(1).通过java程序调用javaapi调用本地方法,

《深入理解Java虚拟机》读书笔记

背景 并发处理的广泛应用是使得Amdahl定律代替摩尔定律成为计算机性能发展的源动力的根本原因,也是人类压榨计算机运算能力最有力的武器 Amdahl 定律通过系统中的并行化与串行化的比重来描述多处理器系统能获得的运算加速能力. 摩尔定律则用于描述处理器晶体管数量与运行效率之间的发展关系. 这两个定律的更替代表了近年来硬件发展从追求处理器频率到追求多核心并行处理的发展过程. 高效并发 物理机上的并发解决方案 在当前这个多核处理器时代,"让计算机并发执行若干个运算任务"和"更充分