走马观花了解jvm spec

目的

  • 深入理解java,学习了解,本文记录一些个人认为有用的一些知识点

1.2 Java虚拟机

  • Java虚拟机与Java语言并没有必然的联系,它只与特定的二进制文件格式——Class文件格式所关联,Class文件中包含了Java虚拟机指令集(或者称为字节码、Bytecodes)和符号表,还有一些其他辅助信息。

2 Java虚拟机结构

  • 如果只是要去“正确地”实现一台Java虚拟机,其实并不如大多数人所想的那样高深和困难——只需要正确读取Class文件之中每一条字节码指令,并且能正确执行这些指令所蕴含的操作即可。

2.2 数据类型

  • 与Java程序语言中的数据类型相似,Java虚拟机可以操作的数据类型可分为两类:原始类型(Primitive Types,也经常翻译为原生类型或者基本类型)和引用类型(Reference Types)。虚拟机中使用reference类型①来表示对某个对象的引用,reference类型的值读者可以想象成类似于一个指向对象的指针。

2.3.4 boolean类型

  • 虽然Java虚拟机定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,在Java语言之中涉及到boolean类型值的运算,在编译之后都使用Java虚拟机中的int数据类型来代替。

2.5 运行时数据区

  • 见文后博客解析

2.11.8 方法调用和返回指令

  • 以下四条指令用于方法调用:
    “`
    invokevirtual指令用于调用对象的实例方法,根据对象的实际类型进行分派(虚方法分派),这也是Java语言中最常见的方法分派方式。
    invokeinterface指令用于调用接口方法,它会在运行时搜索一个实现了这个接口方法的对象,找出适合的方法进行调用。
    invokespecial指令用于调用一些需要特殊处理的实例方法,包括实例初始化方法(§2.9)、私有方法和父类方法。
    invokestatic指令用于调用类方法(static方法)。

而方法返回指令则是根据返回值的类型区分的,
包括有ireturn(当返回值是boolean、byte、char、short和int类型时使用)、
lreturn、freturn、dreturn和areturn,
另外还有一条return指令供声明为void的方法、实例初始化方法、类和接口的类初始化方法使用。
“`

3.12 抛出异常和处理异常

  • 如果在try语句块执行过程中没有异常抛出,程序那么就犹如没有使用try结构一样。(无任何性能损失)

3.14 同步

  • Java虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现。无论是显式同步(有明确的monitorenter和monitorexit指令)还是隐式同步(依赖方法调用和返回指令实现的)都是如此。
  • 在Java语言中,同步用的最多的地方可能是被synchronized修饰的同步方法。同步方法并不是由monitorenter和monitorexit指令来实现同步的,而是由方法调用指令读取运行时常量池中方法的ACC_SYNCHRONIZED标志来隐式实现的。

4.1 ClassFile结构

  • 每一个Class文件对应于一个如下所示的ClassFile结构体

    ClassFile { 
    u4 magic; 
    u2 minor_version; 
    u2 major_version; 
    u2 constant_pool_count; 
    cp_info constant_pool[constant_pool_count-1]; 
    u2 access_flags; 
    u2 this_class; 
    u2 super_class; 
    u2 interfaces_count;
    u2 interfaces[interfaces_count]; 
    u2 fields_count; 
    field_info fields[fields_count]; 
    u2 methods_count; 
    method_info methods[methods_count]; 
    u2 attributes_count; 
    attribute_info attributes[attributes_count]; 
    }

4.3.3 方法描述符

  • 无论mymethod()是静态方法还是实例方法,它的方法描述符都是相同的。尽管实例方法除了传递自身定义的参数,还需要额外传递参数this,但是这一点不是由法描述符来表达的。参数this的传递,是由Java虚拟机实现在调用实例方法所使用的指令中实现的隐式传递。
  • 如果一个方法描述符是有效的,那么它对应的方法的参数列表总长度小于等于255,对于实例方法和接口方法,需要额外考虑隐式参数this。参数列表长度的计算规则如下:每个long和double类参数长度为2,其余的都为1,方法参数列表的总长度等于所有参数的长度之和。(引入限制,方法的参数最多有255个)

4.4 常量池

  • Java虚拟机指令执行时不依赖与类、接口,实例或数组的运行时布局,而是依赖常量池(constant_pool)表中的符号信息。
  • !!!各种重要的常量结构体!!!

4.10.2.5 异常和finally

  • 如果try语句中遇到了return,代码的行为如下:

    1. 如果有返回值的话,将返回值保存在局部变量中。
    2. 执行jsr指令将控制权转到给finally语句中。
    3. 在finally执行完成后,返回事先保存在局部变量中的值。
  • 如果在try语句中有异常抛出,异常处理器的行为是:

    1. 将异常保存在局部变量中。
    2. 执行jsr指令将控制权转到给finally语句中。
    3. 在执行完finally语句后,重新抛出这个事先保存好的异常。

4.11 Java虚拟机限制

    1. 每个类或接口的常量池项最多为65535个
    1. 方法调用时创建的栈帧的局部变量表中的最大局部变量个数65535个
    1. 类或接口中可以声明的字段数最多为65535个
    1. 类或接口中可以声明的方法数最多为65535个
    1. 类或接口的直接父接口最多为65535个
    1. 方法栈帧(§2.6)中的操作数栈的大小深度为65535
    1. 数组的维度最大为255维
    1. 方法的参数最多有255个
    1. 字段和方法名称、字段和方法描述符以及其它常量字符串值(由ConstantValue属性(§4.7.2)引用的值)最大长度为65535个字符

5.3 创建和加载

  • Java虚拟机支持两种类加载器:Java虚拟机提供的引导类加载器(Bootstrap Class Loader)和用户自定义类加载器(User-Defined Class Loader)。每个用户自定义的类加载器应该是抽象类ClassLoader的某个子类的实例。应用程序使用用户自定义类加载器是为了便于扩展Java虚拟机的功能,支持动态加载并创建类。当然,它也可以从用户自定义的数据来源来获取类的二进制表示并创建类。例如,用户自定义类加载器可以通过网络下载、动态产生或是从一个加密文件中提取类的信息。
  • 在Java虚拟机运行时,类或接口不仅仅是由它的名称来确定,而是由一个值对:二进制名称(§4.2.1)和它的定义类加载器共同确定。每个这样的类或接口都归属于独立的运行时包结构(Runtime Package)。类或接口的运行时包结构由包名及类或接口的定义类加载器来决定。

5.4 链接

  • 验证(Verification,§4.10)阶段用于确保类或接口的二进制表示结构上是正确的。
  • 准备(Preparation)阶段的任务是为类或接口的静态字段分配空间,并用默认值初始化这些字段(§2.3,§2.4)。这个阶段不会执行任何的虚拟机字节码指令。在初始化阶段(§5.5)会有显式的初始化器来初始化这些静态字段,所以准备阶段不做这些事情。
  • 解析(Resolution)是根据运行时常量池的符号引用来动态决定具体的值的过程。

5.5 初始化

  • 初始化(Initialization)对于类或接口来说,就是执行它的初始化方法(§2.9)。在发生下列行为时,类或接口将会被初始化:
    1. 在执行下列需要引用类或接口的Java虚拟机指令时:new,getstatic,putstatic或invokestatic。这些指令通过字段或方法引用来直接或间接地引用其它类。执行上面所述的new指令,在类或接口没有被初始化过时就初始化它。执行上面的getstatic,putstatic或invokestatic指令时,那些解析好的字段或方法中的类或接口如果还没有被初始化那就初始化它。
    2. 在初次调用java.lang.invoke.MethodHandle实例时,它的执行结果为通过Java虚拟机解析出类型是2(REF_getStatic)、4(REF_putStatic)或者6(REF_invokeStatic)的方法句柄(§5.4.3.5)。
    3. 在调用JDK核心类库中的反射方法时,例如,Class类或java.lang.reflect包。
    4. 在对于类的某个子类的初始化时。
    5. 在它被选定为Java虚拟机启动时的初始类(§5.2)时。

5.7 Java虚拟机退出

  • Java虚拟机的退出条件一般是:某些线程调用Runtime类或System类的exit方法,或是Runtime类的halt方法,并且Java安全管理器也允许这些exit或halt操作。除此之外,在JNI(Java Native Interface)规范中还描述了当使用JNI API来加载和卸载(Load & Unload)Java虚拟机时,Java虚拟机的退出过程。

第6章 Java虚拟机指令集

第7章 操作码助记符

参考链接

  • https://docs.oracle.com/javase/specs/index.html
  • http://www.amazon.cn/%E5%9B%BE%E4%B9%A6/dp/B00H1FXTNM (有pdf)
  • http://blog.csdn.net/column/details/jvm-principle.html (推荐,图解jvm)

你可能感兴趣的:(java,jvm-spec)