深入理解JVM规范

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文件结构及其子结构中引用的所有字符串常量、类或接口名、字段名和其它常量

   
   
基本类型:B,C,D,F,I,J(long),S,Z(boolen)
对象类型:LClassname;
数组类型:[ArrayType
void: V
Class文件结构示例:
    
    
源码:
 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/1256329
http://en.wikipedia.org/wiki/List_of_Java_virtual_machines

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值