【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.1.类文件结构

无关性

无关性的体现有两个方面:

  1、平台无关性:可在不同的操作系统和机器指令集上执行,可在不同厂商的虚拟机平台上执行。

  2、语言无关性:用不同编程语言写出的代码编译生成的文件都可以运行。

实现思想:

  面向接口,定义虚拟机和编译器之间的接口规范。也就是编译后文件的存储格式——字节码(ByteCode)。

任意一种编程语言,只要生成符合存储格式规范的Class文件,就可以被任意虚拟机执行。

Class文件结构

Class文件结构是在《Java虚拟机规范》中定义的。

Class文件的存储结构类似于C语言的struct。

Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有添加任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。 当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前[1]的方式分割成若干个8位字节进行存储。
Class文件中只有两种类型:无符号数和表。表是无符号数和表表的集合。

Magic Number : 每个Class文件的头4个字节称为魔数(Magic Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接受的Class文件。 固定为 0xCAFEBABE

第5和第6个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)

常量池(constant_pool) 主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References)。
  字面量比较接近于Java语言层面的常量概念,如文本字符串、 声明为final的常量值等。

  符号引用则属于编译原理方面的概念,包括了下面三类常量:类和接口的全限定名(Fully Qualified Name),字段的名称和描述符(Descriptor),方法的名称和描述符

  访问标志(access_flags) 用于识别一些类或者接口层次的访问信息,包括:这个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;如果是类的话,是否被声明为final等。 
类索引(this_class)和父类索引(super_class) 接口索引集合(interfaces)
字段表(field_info)用于描述接口或者类中声明的变量。

  方法表集合 (methods)

  属性表(attribute_info) 在Class文件、 字段表、 方法表都可以携带自己的属性表集合,以用于描述某些场景专有的信息。

Code属性

首先,这是一个属性,位于属性表里面。

Java程序方法体中的代码经过Javac编译器处理后,最终变为字节码指令存储在Code属性内。

Code属性是Class文件中最重要的一个属性,如果把一个Java程序中的信息分为代码(Code,方法体里面的Java代码)和元数据(Metadata,包括类、 字段、 方法定义及其他信息)两部分,那么在整个Class文件中,Code属性用于描述代码,所有的其他数据项目都用于描述元数据。

字节码指令

Java虚拟机的指令由一个字节长度的、 代表着某种特定操作含义的数字(称为操作码,Opcode)以及跟随其后的零至多个代表此操作所需参数(称为操作数,Operands)而构成。

由于Java虚拟机采用面向操作数栈而不是寄存器的架构(这两种架构的区别和影响将在第8章中探讨),所以大多数的指令都不包含操作数,只有一个操作码。

单字节的优势:短小精悍,存储小,传输快。缺点:解析慢,扩展少。

在Java虚拟机的指令集中,大多数的指令都包含了其操作所对应的数据类型信息。  如:iload,fload,dload。

大多数对于boolean、 byte、 short和char类型数据的操作,实际上都是使用相应的int类型作为运算类型

操作类型:加载和存储指令 ,运算指令 ,类型转换指令 ,对象创建与访问指令 ,操作数栈管理指令 ,控制转移指令 ,方法调用和返回指令 ,异常处理指令 ,同步指令 。

一个字节码指令的例子:

void onlyMe(Foo f){
synchronized(f){
doSomething();
}
}

 编译后生成的字节码:

Method void onlyMe(Foo)
0 aload_1//将对象f入栈
1 dup//复制栈顶元素(即f的引用)
2 astore_2//将栈顶元素存储到局部变量表Slot 2中
3 monitorenter//以栈顶元素(即f)作为锁,开始同步
4 aload_0//将局部变量Slot 0(即this指针)的元素入栈
5 invokevirtual#5//调用doSomething()方法
8 aload_2//将局部变量Slow 2的元素(即f)入栈
9 monitorexit//退出同步
10 goto 18//方法正常结束,跳转到18返回
13 astore_3//从这步开始是异常路径,见下面异常表的Taget 13
14 aload_2//将局部变量Slow 2的元素(即f)入栈
15 monitorexit//退出同步
16 aload_3//将局部变量Slow 3的元素(即异常对象)入栈
17 athrow//把异常对象重新抛出给onlyMe()方法的调用者
18 return//方法正常返回
Exception table:
FromTo Target Type
4 10 13 any
13 16 13 any

 

是不是很像汇编? 这样理解也应该可以:字节码就是虚拟机上的汇编语言。

再总结一下

class文件格式,是在JVM虚拟机和各种语言编译器之间的接口。

只要符合这个接口规范,任何语言的任何编译器,编出来的class文件,都可以在任何JVM虚拟机上运行。

Class文件分两部分:1、元数据,2、字节码指令集。

这些内容与硬件、 操作系统及具体的Java虚拟机实现之间是完全独立的,虚拟机实现者可能更愿意把它们看做是程序在各种Java平台实现之间互相安全地交互的手段。

虚拟机实现的方式主要有以下两种:
将输入的Java虚拟机代码在加载或执行时翻译成另外一种虚拟机的指令集。     -- 好处:适应于各种硬件环境。
将输入的Java虚拟机代码在加载或执行时翻译成宿主机CPU的本地指令集(即JIT代码生成技术)。  -- 好处:提升热点函数的执行速度。  HotSpot的命名即来于此。

原文地址:https://www.cnblogs.com/aoyihuashao/p/10348761.html

时间: 2024-08-26 16:59:23

【深入理解JAVA虚拟机】第三部分.虚拟机执行子系统.1.类文件结构的相关文章

深入理解JVM读书笔记三: 虚拟机类加载机制

Java虚拟机类加载机制是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 7.1概述 与那些在编译时需要进行链接工作的语言不同,在Java语言里面,类型的加载和链接过程都是在程序运行期间完成的(其实C++也是分为静态链接库和动态链接库的),这样会在类加载时稍微增加一些性能开销,但是却能为Java应用程序提供高度的灵活性,Java中天生可以动态扩展的语言特性就是依赖运行期动态加载和动态链接这个特点实现的. 7.

(3) 深入理解Java Class文件格式(三)

转载:http://blog.csdn.net/zhangjg_blog/article/details/21557357 首先, 让我们回顾一下关于class文件格式的之前两篇博客的主要内容. 在 深入理解Java Class文件格式(一) 中, 讲解了class文件在整个java体系结构中的位置和作用, 讲解了class文件中的魔数和版本号相关的信息, 并且对常量池进行了概述. 在 深入理解Java Class文件格式(二) 中, 主要讲解了class文件中的特殊字符串, 包括类的全限定名,

jvm性能调优(三)-----JVM的执行子系统

Class类文件结构 Java跨平台的基础 各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(ByteCode)是构成平台无关性的基石,也是语言无关性的基础.Java虚拟机不和包括Java在内的任何语言绑定,它只与“Class文件”这种特定的二进制文件格式所关联,Class文件中包含了Java虚拟机指令集和符号表以及若干其他辅助信息. Class类的本质 Class文件是一组以8位字节为基础单位的二进制流 类似于结构体的伪结构来存储数据 只有两种数据类型:无符号数和表 无符号数属

理解 Java GC(三)

本文主要讲解下GC的5中类型: Serial GC (-XX:+UseSerialGC) Parallel GC (-XX:+UseParallelGC) Parallel Old GC(-XX:+UseParallelOldGC) CMS GC (-XX:+UseConcMarkSweepGC) G1 GC Serial GC (-XX:+UseSerialGC) 在之前的文章里,我们已经讲解过GC在 young generation采用的GC算法了.GC在 old generation采用的

深入理解JAVA集合系列三:HashMap的死循环解读

由于在公司项目中偶尔会遇到HashMap死循环造成CPU100%,重启后问题消失,隔一段时间又会反复出现.今天在这里来仔细剖析下多线程情况下HashMap所带来的问题: 1.多线程put操作后,get操作导致死循环. 2.多线程put非null元素后,get操作得到null值. 3.多线程put操作,导致元素丢失. 死循环场景重现 下面我用一段简单的DEMO模拟HashMap死循环: 1 public class Test extends Thread 2 { 3 static HashMap<

Java基础---IO(三)--IO包中的其他类

第一讲     对象序列化 一.概述 将堆内存中的对象存入硬盘,保留对象中的数据,称之为对象的持久化(或序列化).使用到的两个类:ObjectInputStream和ObjectOutputStream 二.特有方法 ObjectInputStream: Object readObject();//从ObjcetInputStream中读取对象 ObjectOutputStream: void writeObject(Objcet obj);//将指定对象写入ObjcetOutputStream

Java并发编程(三) 并发类库中的常用类

1. 同步容器类 遗留下来的同步容器类包括Vector和Hashtable,此外java.util.Collections类中还提供了以下工厂方法创建线程安全的容器对象: Collections.synchronizedList 返回支持同步操作(线程安全)的List对象: Collections.synchronizedSet 返回支持同步操作(线程全的)的Set对象: Collections.synchronizedMap 返回支持同步操作(线程安全)的Map对象: 需要注意的是,同步容器类

深入理解Java虚拟机(第三版)-14. 线程安全与锁优化

14. 线程安全与锁优化 1. 什么是线程安全? 当多个线程同时访问一个对象时,如果不用考虑这些线程在运行时环境下的调度和交替进行,也不需要进行额外的同步,或者在调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那就称这个对象是线程安全的 2. Java语言中的线程安全 我们将Java语言下的线程安全分为以下五类:不可变.绝对线程安全.相对线程安全.线程兼容和线程对立. 1.不可变:不可变一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要进行任何线程安全保障措施

《深入理解Java虚拟机:JVM高级属性与最佳实践》读书笔记(更新中)

第一章:走进Java 概述 Java技术体系 Java发展史 Java虚拟机发展史 1996年 JDK1.0,出现Sun Classic VM HotSpot VM, 它是 Sun JDK 和 OpenJDK 中所带的虚拟机,最初并不是Sun开发 Sun Mobile- Embedded VM/ Meta- Circular VM BEA JRockit/ IBM J9 VM JRockit曾号称世界上最快的java虚拟机,BEA公司发布.J9属于IBM主要扶持的虚拟机 Azul VM/ BEA