认识JVM(初识class文件)

认识class文件的好处:
1、加强对Java的理解
2、通过修改class或生成新的class方式完成项目功能(如spring就是通过修改class文件来完成功能的)
3、为热修复热部署功能完成第一步

程序员编写的Java文件经过javac编译生成class文件,jvm加载class文件并执行Java代码从而实现各种业务逻辑。class文件记录了程序员编写的代码信息,包括编译的jdk版本、class类名、方法名、参数等信息。
编写Test.java代码如下:

    public class Test {
        String a ="abc";
        public void printA(){
            System.out.println(a);
        }
    }

通过命令行javac Test.java 编译生成Test.class文件
通过命令行javap -c Test.class 查看class文件如下图所示
认识JVM(初识class文件)_第1张图片
如上所示,class文件包含了类名、临时变量、方法
jvm加载class之后,执行了方法中的指令集就完成了方法的调用,以构造方法为例解释如下:
1、jvm在调用构造方法前,在内存栈中创建栈帧用来存放构造方法中的参数、变量、并通过计算生成返回值
(这里注意一点:jvm创建栈帧也需要申请内存,如果递归方法没能及时退出可能导致内存溢出)

2、执行指令:
  0: aload_0 加载第0个地址变量到栈顶(即this指针)
  1: invokespecial #1 调用常量池中索引为1的方法init (即调用构造方法,构造方法都用init表示)
  4: aload_0 同上
  5: ldc #2 加载常量池中索引为2的常量值abc到栈顶 (这里只是对常量abc的引用,即加载常量abc的指针)
  7: putfiled #3 用栈顶的值赋值给类的实例,该实例是常量池中索引为3的的变量 (即把abc常量值赋值给变量a)
  10: return 返回指令

3、执行完2步的指令集,当前栈帧结束,若需要调用下一个方法则会创建新的栈帧作为当前栈帧
如上,常量池中的索引及其值可以通过javap -v Test.class 命令行查看详细信息:
认识JVM(初识class文件)_第2张图片
以上还可以通过另外一种方式查看class文件,以nodepad++为例,打开class文件 -> 选择插件 -> HEX-Editor -> View in HEX
(若未安装此插件,可自行百度安装插件)
如下图所示:
认识JVM(初识class文件)_第3张图片
ca fe ba be 称为魔数,用来识别该文件是class文件(该单词翻译是咖啡男孩,与jdk的咖啡Logo一致)
副版本、主版本用来确定class文件是那个jdk版本编译的
常量池计数器 常量池count数量
再之后就是常量池了,常量池中主要存放了字面量和符号引用两部分
字面量包括字符串,基本类型的常量泛指常量池中的值,符号引用就是常量池里面的字符串索引
认识JVM(初识class文件)_第4张图片

如上介绍,class文件中记录的信息和jvm内存模型是相互对应的。
Java虚拟机JVM的内存模型分为:程序计数器、堆、栈、方法区
1、程序计数器用来存放指令集 详细指令集可参考《Java虚拟机规范》一文或博客:https://blog.csdn.net/hudashi/article/details/7062675 https://blog.csdn.net/hudashi/article/details/7062781
2、堆 用来存放和回收对象,程序员通过new 方法产生的对象和GC回收都在此处完成
3、栈 创建栈帧并执行指令集在此处完成
4、方法区 用来存放class文件的信息
方法区又包含了运行时常量池,方法区存放魔数、版本号 而常量池计数器和其他信息都存放在运行时常量池

你可能感兴趣的:(Java)