加载阶段
- 加载阶段第一步是类加载器根据类的全限定名通过不同渠道以二进制流的方式获取字节码信息。
- 本地文件:磁盘上的字节码文件
- 动态代理生成:程序运行时使用动态代理生成
- 通过网络传输的类:早期的Applet技术使用
- 类加载器在加载完类以后,Java虚拟机会将字节码中的信息保存到内存的方法区中。
生成一个InstanceKlass对象,保存类的所有信息,里面还包含实现特定功能比如多态的信息
- java虚拟机还会在堆中生成一份与方法区中数据类似的java.lang.Class对象(方法区中的是c++,java不能直接操作)。
作用是在java代码中去获取类的信息以及存储静态字段的数据 (jdk8以后),
- 对于开发者来说,只需要访问堆中的Class对象而不需要访问方法区中所有信息。
这样Java虚拟机就能很好地控制开发者访问数据的范围
查看内存中的对象
- 使用jdk自带的hsdb工具查看java虚拟机内存信息。工具位于JDK安装目录下lib文件夹中的sa-jdi.jar中。
- 启动命令:java -cp sa-jdi.jar sun.jvm.hotspot.HSDB (指定启动类)
-
- 打开后界面如下图所示
- 点击file->attach to hotspot process后跳出弹窗,在弹窗中输入要查看的进程号,进程号可以通过在cmd中输入jps查看。
- 打开tools->object histogram搜索要查看的类,之后双击该类,就可以查看该类的信息。
连接阶段
验证
连接的第一个环节是验证,验证的主要目的是检测Java字节码文件是否遵守了《java虚拟机规范》中的约束。
主要分以下四个部分
- 文件格式验证,比如文件是否以cafebabe开头,主次版本号是否满足当前java虚拟机版本的要求。
- 元信息验证,例如类必须有父类
- 验证程序执行指令的语义,比如方法内的指令执行中跳转到不正确的位置。
- 符号引用验证,例如是否访问了其他类中private的方法等。
准备
准备阶段为静态变量分配内存并设置初始值(jdk8以后的版本)
解析
- 解析阶段主要是将常量池中的符号引用替换为直接引用。
- 符号引用就是在字节码文件中使用编号来访问常量池中的内容。
- 直接引用不再使用编号,而是使用内存中地址进行访问具体的数据。