如何经营自己的网站快速开发平台
Java虚拟机
Java虚拟机的组成
Java虚拟机的组成由类加载器ClassLoader、运行时数据区域(JVM管理的内存)和执行引擎(即时遍历器、解释器垃圾回收器)
- 类加载器加载class字节码文件中的内容到内存
- 运行时数据区域负责管理jvm使用到的内存,比如创建对象和销毁对象
- 执行引擎将字节码文件中的指令解释称机器码,同时使用即时编译器优化性能
字节码文件的组成
字节码文件的组成由基础信息、常量池、字段、方法和属性
基础信息
魔数、字节码文件对应的Java版本号、访问标识(public final等等)、父类和接口
Magic魔数
- 文件是无法通过文件扩展名来确定文件类型的,文件扩展名可以随意修改,不影响文件的内容
- 软件使用文件的头几个字节(文件头)去校验文件的类型,如果软件不支持该种类型就会出错
- Java字节码文件中国,将文件头成为magic魔数
文件类型 | 字节数 | 文件头 |
---|---|---|
jpg | 3 | FFD8FF |
png | 4 | 89504E47 |
bmp | 2 | 424D |
xml | 5 | 3C3F786D6C |
avi | 4 | 41564920 |
java字节码文件 | 4 | CAFEBABE |
主副版本号
- 主副版本号指的是编译字节码文件的JDK版本号,主版本号用来标识大版本号,JDK1.0-1.1使用了45.0-45.3,JDK1.2是46之后每升级一个大版本就加1;副版本号是当主版本号相同时作为区分不通过版本的标识,一般只需要关心主版本号
- 版本号的作用主要是判断当前字节码的版本和运行时的JDK是否兼容
名称 | 作用 |
---|---|
Magic魔数 | 固定位0xCAFEBABE |
副版本号 | |
主版本号 | 编译字节码文件的JDK版本 |
访问标识 | 标识是类还是接口、注解、枚举、模块标识public final abstract |
类、父类、接口索引 | 通过这些索引可以找到类、父类、接口的信息 |
常量池
保存了字符串常量、类或接口名、字段名,主要在字节码指令中使用
- 字节码文件中常量池的作用:避免相同的内容重复定义,节省空间
- 常量池中的数据都有一个编号,编号从1开始。在字段或者字节码指令中通过编号可以快速的找到对应的数据
- 字节码指令中通过编号引用到常量池的过程称之为符号引用
方法
当前类或接口声明的方法信息字节码指令
- 操作数栈是临时存放数据的地方,局部变量表是存放方法中的局部变量的位置
类的生命周期
加载阶段
-
加载阶段第一步是类加载器根据类的全限定名通过不同的渠道以二进制流的方式获取字节码信息
-
类加载器在加载完类之后,Java虚拟机会将字节码中的信息保存到方法区中
生成一个InstanceKlass对象,保存类的所有信息,里边还包含实现特定功能比如多态的信息
-
同时,Java虚拟机还会在堆中生成一份与方法区中数据类似的java.lang.Class对象
作用是在Java代码中去获取类的信息以及存储静态字段的数据(JDK8及之后)
- 推荐使用JDK自带的hsdb工具查看Java虚拟机内存信息。工具位于JDK安装目录下lib文件夹中的sa-jdi.jar中
- 启动命令:java -cp sa-jdi.jar sun.jvm.hotspot.HSDB
连接阶段
连接阶段分为验证、准备和解析
验证的主要目的是验证内容是否满足《Java虚拟机规范》
准备的主要目的是给静态变量赋初值
解析的主要目的是将常量池中的符号引用替换成指向内存的直接引用
初始化阶段
- 初始化阶段会执行静态代码块中的代码,并为静态变量赋值
- 初始化阶段会执行字节码文件中clinit部分的字节码指令