《The Java Virtual Machine Specification》阅读笔记

jvm规范代表了jvm的标准,任何jvm的实现都要遵守该标准,所以阅读jvm规范对理解jvm是有意义的。目录如图

有目录大概可以猜测到: 

第一章是关于jvm的历史、背景与综述;

第二章是jvm的结构

第三章是编译

第四章开始详细说明class文件的格式

第五章是整个装载编译链接的步骤

第六章是指令集

第七章是助记符

直接跳过第一章,看第二章

很显然,这一章就是描述一下jvm中的结构。 

第一节粗略介绍了一下class格式,就是说编译后要被jvm执行的代码使用一种独立于操作系统与硬件的二进制格式,称为class格式,class定义了类和接口的一切。

第二节介绍数据类型,分为基本类型primitive types和引用类型reference types。jvm规定了在运行之前需要进行类型检查,一般是由编译器完成,不应该让jvm亲自做类型检查。并且在类型检查时不同的基本类型不必做标记。相反,jvm的运行时的指令会做区分,操作不同的类型会有不同的指令。比如,iadd操作int,ladd操作long,fadd操作float等等。jvm中的对象object要么是动态创建的class实例,要么是数组,引用类型就是对象的引用,它的值可以被认为是指向对象的指针,一个对象通常会有多个指向自己的引用。

第三节详细介绍基本数据类型,分为数字型numeric 、布尔型型boolean 和returnAddress型。数字型又分为整型和浮点型。整型有byte:8个bit,默认值是0;short:16个bit,默认为0;int:32个bit,默认值是0;long:64个bit,默认为0;char:16个bit,默认为null。浮点型有float和double。布尔型默认值是false。returnAddress 是指向操作码的指针,并不是编程时能使用的类型。接下来是一些琐碎的内容,先跳过。

第四节详细介绍引用类型,分为类类型、数组类型和接口类型。他们的值是对类或数组实例的引用。数组可以包含数组、包含数组的数组……,但最终必须有一个非数组类型。引用类型的默认值是null-----不是任何对象的引用,也没有运行时类型,可以转换成任何类型。

第五节介绍运行时数据区,一些运行时数据区会在jvm启动时创建,在jvm关闭时销毁。另一些的数据区是基于线程的,线程创建时创建线程离开时销毁。主要有一下几种运行时数据区:

1、pc注册器 program counter register,每个jvm线程在任何阶段都会有一个当前正在执行的方法,当前线程的pc注册器会记录当前执行的指令的地址,如果当前执行的是native(暂时不知道是什么),pc注册器则为undefine。生命周期和线程一样。

2、栈stack,每个jvm线程创建时会同时创建私有栈,用来存储本地变量、函数调用和返回,这个栈只能push和pop,不能手动操作。栈不一定是内存连续的。栈既能修改尺寸又能动态扩展。相关的异常为:StackOverflowError、OutOfMemoryError。生命周期和线程一样。

3、堆heap,堆是被所以线程所共享的,存储所有的类和数组的实例,这些实例会被垃圾收集器自动回收。不过垃圾收集器是由jvm的具体实现提供的,jvm对此没有做出明确的规范。堆也是可以修改尺寸、动态扩展尺寸的,也不需要内存连续。对应的异常为OutOfMemoryError。生命周期和jvm一样。

4、方法区method area,方法区是被所有线程所共享的,用来存储编译后的代码,包括每个class的结构,例如方法、属性、静态池、构造器等等。生命周期和jvm一样。方法区从逻辑上来说是属于堆的。但是jvm规范并没有规定其位置,由具体实现自主选择。既能修改尺寸又能动态扩展尺寸也不需要内存连续。相关异常为OutOfMemoryError。

5、运行时静态池run-time constant pool,每个类或接口都由一个静态池,具体表现就是class文件的constant_pool表。这个后面会详细介绍。

6、原生方法栈native method stacks,原生方法栈用来存储非java语言的方法,例如c语言。一般被jvm或解释器使用,被解释器使用时会被解释为jvm指令来执行。不能装载原生方法的jvm实现就不应该提供原生方法栈,如果提供了,它应该属于线程在线程创建时创建。既能修改尺寸又能动态扩展尺寸。相关异常为StackOverflowError,OutOfMemoryError。

第六节介绍帧,当一个方法执行时就会创建一个新的帧,用来存储数据、部分结果、方法返回值等等,方法执行完就会被销毁。帧位于每个线程的栈中,每个帧有自己的本地变量数组、操作数栈和当前方法所属的类的运行时静态池的引用。在线程执行时,同一时刻只会有一个帧、一个方法、一个类,分别被称为当前帧current frame、当前方法current method、当前类current class。当当前帧的方法调用了另一个方法,当前帧便不再是当前的,一个新的帧会被创建并且称为当前帧,控制权也会转移到新方法中。当方法返回时,如果有返回值,当前帧会把它返回到上一帧,然后上一帧会成为当前帧。注意!帧是不能被其他线程引用的。

1、本地变量和操作数栈

每个帧都包含一个本地变量数组,下标由0开始,long和double占2个连续的下标,其他占一个。占两个下标时,由前一个下标定位。当类的方法调用时,会通过本地变量数组传递参数,下标由0开始依次取;当实例的方法调用时,会通过本地变量数组传递参数,下标由1开始,而下标0则指向当前实例对象,即java语言中的this。每个帧也包含一个后进先出的操作数栈,当帧刚创建时,操作数栈是空的,jvm会提供指令来加载来自本地变量或对象实例的常数或值到操作数栈,然后jvm的一些指令会操作操作数栈pop出的值,再将结果push到操作数栈。例如,iadd指令会将两个int送入操作数栈,然后pop出他们,再将二者之和push入操作数栈。

//TODO下班了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值