2. JVM基础
1 java从编码到执行
2 从跨平台到跨语言
- jvm相当于虚构出来的一个计算机,有自己的字节码指令集,即自己的汇编语言,也有自己的内存管理方案:栈、堆、方法区
- jvm跟java语言无关,跟class有关,只要语言能编译成class,jvm就能执行
- jvm是一种规范,调优是针对这个规范的来具体实现
- 常见的jvm实现
- HotSpot:Oracle公司
- Jrockit:已与HotSpot合并
- J9:IBM公司
- Microsoft VM
- TaobaoVM:hotspot深度定制版
- Liquid VM:直接针对硬件
- zing:azul公司,很贵,垃圾回收快,业界标杆,ZGC就是参考的zing里的实现
- 所谓的java8以后都收费,是虚拟机收费,而不是java语言本身收费,我们可以使用openjdk、TablBaoVM,这些内涵开源的hotspot版本的jdk,免费使用
- jdk、jre、jvm间关系
- jdk = jre+development kit
- development kit包括一些调试的工具,jdk目录里,除了jre,都是jdk的内容
- jre = jvm+core lib
- jvm
- jdk = jre+development kit
3 翻译.class文件
- 可以使用sublime、notepad、Intellij的BinEd,将.class文件以16进制码或2进制码打开
- BinEd:File–Open As Binary,选项Binary为二进制显式,HEX为16进制
- 这个二进制字节流,是由java虚拟机进行解释
- 字节流中的数据类型
- u1:1个字节的无符号整数,1个字节应该是8位二进制数,也就是2位的16进制数
- u2:2字节
- u4:4字节
- u8:8字节
- _info:表类型,是hotspot源码中的写法
- 几个位置字节的含义
- 1-4字节:Magic Number,CA FE BA BE:表示文件类型为javac编译的class文件
- 5-8字节:表示版本号,2个字节的Minor Version小版本号+2字节的Major Version大版本号,java1.8对应的大版本号值就是十六进制的0034,即52
- 9-10字节:constant_pool_count,表示常量池中有多少内容,由于占用2个字节,因此最多存放2的16次方个常量,但由于常量池中,预留了一位不允许使用,因此常量池实际上可以存放constant_pool_count-1个常量
- constant_pool:长度为constant_pool_count-1的一张表(数组),编号从1 开始,0号做了预留,里面内容特别繁琐
- access_flags:修饰class的一些关键字,使用按位或运算,例如0x0421,表示0x0001(public)|0x0020(invokespectial为真)|0x0400(abstract),也就是说,该类由public abstract修饰
- this_class:当前的class,是常量池中的哪个常量表示
- supper_class:
- interfaces_count
- interfaces
- fields_count
- fields
- methods_count
- methods
- attributes_count
- attributes
- 直接看二进制或十六进制码过于费劲,可以使用工具对class中内容进行翻译
- javap -v class位置
- JBE:java bytecode editor可以直接修改二进制码
- JClass-Lib:IDEA插件,安装好后,鼠标点进class里,view–Show bytecode with jclasslib
- 每一个常量,第1个字节都表示常量的类型,从1到18分别有不同的含义
- CONSTANT_Utf8_info:可以理解为一个utf8编码格式的字符对象
- CONSTANT_Methodref_info:可以理解为一个存放方法引用信息的对象,该对象中含有两个引用,这两个引用通过二进制码0002与000D所表示的常量池中的第2和第13个常量,即一个指向表示当前方法所在类的CONSTANT_Class_info对象,另一个指向表示方法名和类型的CONSTANT_NameAndType对象
- CONSTANT_NamedAndType_info:该对象也包含两个引用,一个指向第4个表示方法名的CONSTANT_Utf8_info对象,一个指向第5个表示方法返回值的CONSTANT_Utf8_info对象。其中<init>表示该方法为初始化方法,<()V>表示该方法无参,且返回值为void
- 具体(V)表示的含义,可以参考图中methods-descriptor_index中的解释,以及fields-descriptor_index中的解释,注意该图中涉及到index,都表示在常量值中的元素位置
- methods中会有一些附加属性,而Code属性是其中最重要的那个,表示代码是怎么实现的,比如对于该方法,字节码指令为2ab70001b1,JVM将2a转为JVM中为汇编指令aload_0,表示将方法局部变量表中第0项(this),扔到操作数栈中,然后将b7转为invokespecial,表示调用this的构造方法,然后将这个方法后面4位0001所指向常量池中第一个常量的构造方法,为Object构造方法,进行调用,所以创建对象前,会先调用父类构造器。最后JVM将这些指令一条条的执行
- java指令集最多有256个,指令可以在java虚拟机规范文档中,找到对应的含义