JVM的概念
- JVM是什么:
Java Virtual Machine ,Java 虚拟机
1)一种抽象的计算机,可以执行Java字节码,有自己的指令集和内存结构; 2)屏蔽了底层的操作系统和硬件体系结构,从而实现了“Write Once,Run Anywhere”; 3)按照“JVM规范”实现。
- JVM的实现
1)Oracle公司的HotSpot(对应开源的OpenJDK); 2)Oracle公司的JRockit(BEA Systems); 3)Apache社区开源的Apache Harmony; 4)Google的Dalvik; 5)IBM公司的J9;
- JVM 工作原理示例
- JVM的结构
- 数据类型
- 运行时数据区
- 栈帧
- 异常
- 浮点运算
- 字节码指令集
- 类库
- ...
数据类型
1)基本类型(Primitive Type)
数值型: byte,short,int,long,char,float,double 布尔类型:boolean returnAddress类型:JVM特有的,被jsr,ret,jsr_w指令所使用,对应的值指向一条虚拟机指令的操作码,唯一无法与 Java语言基本类型对应的原始类型。2)引用类型(Reference Type)
类或接口类型; 数组类型。
运行时数据区
PC寄存器(Program Counter) 保存当前执行方法中正在执行的字节码指令的地址 JAVA虚拟机栈(JVM Stack) 存储执行的栈帧;StackOverflowError/OutOfMemeryError JAVA堆(JVM Heap) 线程共享,存储类实例,数组实例,接口实现实例; OutOfMemeryError 方法区(Method Area) 线程共享,存储类结构信息(运行时常量池、字段、方法Code属性、构造函数和普通方法的实现);OutOfMemeryError 运行时常量池 类或接口的常量池的运行时表示形式 本地方法栈(Native Stack) 使用其它语言(例如C语言)编写的方法,JNI调用
栈帧
Class文件结构![]()
常量池是一种表结构,它包含了Class文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量
Class文件结构示例:基本类型:B,C,D,F,I,J(long),S,Z(boolen) 对象类型:LClassname; 数组类型:[ArrayType void: V
源码:public class HelloWorld{ public int hello(String txt) { System.out.println(txt); return 1; } private void test1() { } protected void test2(long t) { String txt = "Hello,Wolrd"; { int i = 11; } int j = 12; } }
二进制形式解读
反编译后的汇编形式(javap -private -verbose HelloWorld)
Compiled from "HelloWorld.java" public class HelloWorld extends java.lang.Object SourceFile: "HelloWorld.java" minor version: 0 major version: 50 Constant pool: const #1 = Method #6.#28; // java/lang/Object."<init>":()V const #2 = Field #29.#30; // java/lang/System.out:Ljava/io/PrintStream; const #3 = Method #31.#32; // java/io/PrintStream.println:(Ljava/lang/String;)V const #4 = String #33; // Hello,Wolrd const #5 = class #34; // HelloWorld const #6 = class #35; // java/lang/Object const #7 = Asciz <init>; const #8 = Asciz ()V; const #9 = Asciz Code; const #10 = Asciz LineNumberTable; const #11 = Asciz LocalVariableTable; const #12 = Asciz this; const #13 = Asciz LHelloWorld;; const #14 = Asciz hello; const #15 = Asciz (Ljava/lang/String;)I; const #16 = Asciz txt; const #17 = Asciz Ljava/lang/String;; const #18 = Asciz test1; const #19 = Asciz test2; const #20 = Asciz (J)V; const #21 = Asciz i; const #22 = Asciz I; const #23 = Asciz t; const #24 = Asciz J; const #25 = Asciz j; const #26 = Asciz SourceFile; const #27 = Asciz HelloWorld.java; const #28 = NameAndType #7:#8;// "<init>":()V const #29 = class #36; // java/lang/System const #30 = NameAndType #37:#38;// out:Ljava/io/PrintStream; const #31 = class #39; // java/io/PrintStream const #32 = NameAndType #40:#41;// println:(Ljava/lang/String;)V const #33 = Asciz Hello,Wolrd; const #34 = Asciz HelloWorld; const #35 = Asciz java/lang/Object; const #36 = Asciz java/lang/System; const #37 = Asciz out; const #38 = Asciz Ljava/io/PrintStream;; const #39 = Asciz java/io/PrintStream; const #40 = Asciz println; const #41 = Asciz (Ljava/lang/String;)V; { public HelloWorld(); Code: Stack=1, Locals=1, Args_size=1 0: aload_0 1: invokespecial #1; //Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 1: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this LHelloWorld; public int hello(java.lang.String); Code: Stack=2, Locals=2, Args_size=2 0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: aload_1 4: invokevirtual #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 7: iconst_1 8: ireturn LineNumberTable: line 4: 0 line 5: 7 LocalVariableTable: Start Length Slot Name Signature 0 9 0 this LHelloWorld; 0 9 1 txt Ljava/lang/String; private void test1(); Code: Stack=0, Locals=1, Args_size=1 0: return LineNumberTable: line 9: 0 LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LHelloWorld; protected void test2(long); Code: Stack=1, Locals=5, Args_size=2 0: ldc #4; //String Hello,Wolrd 2: astore_3 3: bipush 11 5: istore 4 7: bipush 12 9: istore 4 11: return LineNumberTable: line 12: 0 line 14: 3 line 16: 7 line 17: 11 LocalVariableTable: Start Length Slot Name Signature 7 0 4 i I 0 12 0 this LHelloWorld; 0 12 1 t J 3 9 3 txt Ljava/lang/String; 11 1 4 j I }
加载、连接及初始化
![]()
- 加载阶段
根据类或接口的名称,查找对应的二进制文件,然后根据二进制数据流创建对应的类或接口表示形式; 伴随着Class文件的格式检查: 1)开头的四个字节是否为魔术; 2)预定义的属性是否符合对应的长度; 3)是否含有为被规范定义的信息; 4)文件是否缺少或多出额外的字节; 5)...
- 连接(验证)
1)按照JVM规范描述的Class文件的静态约束和结构化约束检查; 2)按照JVM规范描述的类型检查及类型推导检查来验证是否符合Java语言规范的要求,已经会危害虚拟机的安全运行; 3)整体归纳总结为如下四个阶段: 文件格式验证、元数据验证、字节码验证和符号引用验证
- 连接(准备及解析)
准备:
为类或接口的静态变量分配空间,使用默认值初始化;解析:
将常量池中的符号引用替换为直接引用的过程; 类或接口解析、字段解析、类方法解析及接口方法解析;
- 初始化
1)执行类或接口的初始化方法<clinit>,这个是由编译器自动生成的; 2)虚拟机会保证对一个类的<clinit>方法,在多线程环境中,被正确的加锁同步。参考链接
http://docs.oracle.com/javase/specs/jvms/se7/jvms7.pdf http://icyfenix.iteye.com/blog/1256329http://en.wikipedia.org/wiki/List_of_Java_virtual_machines