自己动手写Java虚拟机

/ 书籍 / 0 条评论 / 1076浏览 / 我要评论

下载

电子版仅供预览及学习交流使用,下载后请24小时内删除,支持正版,喜欢的请购买正版书籍

封页

封页

编辑推荐

   

内容简介

Java虚拟机非常复杂,要想真正理解它的工作原理,最好的方式就是自己动手编写一个! 本书是继《深入理解Java虚拟机》之后的又一经典著作,它一方面遵循《Java虚拟机规范》,一方面又独辟蹊径,不仅能让Java虚拟机的学习变得更加简单和有趣,而且能让你对Java虚拟机的原理认识更深入和更深刻! 本书摒弃了传统的以解读枯燥的Java虚拟机规范文档和分析繁琐的Java虚拟机源代码的方式来讲解Java虚拟机,取而代之的是,以实践的方式,引导读者如何从零开始构建和实现一个Java虚拟机,整个过程不仅能让读者做到对Java虚拟机知其然而且知其所以然,还能屏蔽大量不必要的繁琐细节,体会到实现过程中的成就感,让学习过程更加轻松、愉悦和高效。更重要的是,这种方式能引导读者更深入地认识和掌握Java虚拟机的工作原理。  

作者简介

张秀宏  资深Java服务器开发工程师,有多年的Java开发、游戏服务器开发和架构经验,对Java虚拟机有非常深入的研究。曾在EA、华娱无线等游戏公司担任高级服务器工程师职位,现任乐元素Lead软件工程师。

目 录

目  录 Contents

前言

1章 命令行工具 1

1.1
 准备工作 1

1.1.1
 安装JDK 1

1.1.2
 安装Go 2

1.1.3
 创建目录结构 3

1.2
 java命令 4

1.3
 编写命令行工具 5

1.4
 测试本章代码 7

1.5
 本章小结 8

2章 搜索class文件 9

2.1
 类路径 9

2.2
 准备工作 10

2.3
 实现类路径 11

2.3.1
 Entry接口 12

2.3.2
 DirEntry 13

2.3.3
 ZipEntry 14

2.3.4
 CompositeEntry 15

2.3.5
 WildcardEntry 17

2.3.6
 Classpath 17

2.4
 测试本章代码 20

2.5
 本章小结 21

3章 解析class文件 23

3.1
 class文件 24

3.2
 解析class文件 25

3.2.1
 读取数据 26

3.2.2
 整体结构 27

3.2.3
 魔数 30

3.2.4
 版本号 31

3.2.5
 类访问标志 32

3.2.6
 类和超类索引 32

3.2.7
 接口索引表 33

3.2.8
 字段和方法表 33

3.3
 解析常量池 35

3.3.1
 ConstantPool结构体 35

3.3.2
 ConstantInfo接口 37

3.3.3
 CONSTANT_Integer_info 39

3.3.4
 CONSTANT_Float_info 40

3.3.5
 CONSTANT_Long_info 40

3.3.6
 CONSTANT_Double_info 41

3.3.7
 CONSTANT_Utf8_info 42

3.3.8
 CONSTANT_String_info 43

3.3.9
 CONSTANT_Class_info 45

3.3.10
 CONSTANT_NameAnd-Type_info 46

3.3.11
 CONSTANT_Fieldref_info

 CONSTANT_Methodref_infoCONSTANT_Interface-Methodref_info 47

3.3.12
 常量池小结 49

3.4
 解析属性表 50

3.4.1
 AttributeInfo接口 50

3.4.2
 DeprecatedSynthetic属性 53

3.4.3
 SourceFile属性 54

3.4.4
 ConstantValue属性 55

3.4.5
 Code属性 56

3.4.6
 Exceptions属性 58

3.4.7
 LineNumberTable

 LocalVariableTable属性 59

3.5
 测试本章代码 61

3.6
 本章小结 63

4章 运行时数据区 65

4.1
 运行时数据区概述 66

4.2
 数据类型 67

4.3
 实现运行时数据区 68

4.3.1
 线程 68

4.3.2
 Java虚拟机栈 69

4.3.3
 帧 71

4.3.4
 局部变量表 72

4.3.5
 操作数栈 74

4.3.6
 局部变量表和操作数栈实例分析 76

4.4
 测试本章代码 81

4.5
 本章小结 83

5章 指令集和解释器 85

5.1
 字节码和指令集 86

5.2
 指令和指令解码 88

5.2.1
 Instruction接口 89

5.2.2
 BytecodeReader 91

5.3
 常量指令 92

5.3.1
 nop指令 92

5.3.2
 const系列指令 93

5.3.3
 bipushsipush指令 94

5.4
 加载指令 94

5.5
 存储指令 95

5.6
 栈指令 96

5.6.1
 poppop2指令 96

5.6.2
 dup指令 97

5.6.3
 swap指令 98

5.7
 数学指令 98

5.7.1
 算术指令 98

5.7.2
 位移指令 99

5.7.3
 布尔运算指令 101

5.7.4
 iinc指令 102

5.8
 类型转换指令 102

5.9
 比较指令 103

5.9.1
 lcmp指令 103

5.9.2
 fcmpdcmp指令 104

5.9.3
 if指令 105

5.9.4
 if_icmp指令 106

5.9.5
 if_acmp指令 107

5.10
 控制指令 108

5.10.1
 goto指令 108

5.10.2
 tableswitch指令 108

5.10.3
 lookupswitch指令 110

5.11
 扩展指令 111

5.11.1
 wide指令 111

5.11.2
 ifnullifnonnull指令 113

5.11.3
 goto_w指令 113

5.12
 解释器 114

5.13
 测试本章代码 118

5.14
 本章小结 120

6章 类和对象 121

6.1
 方法区 122

6.1.1
 类信息 122

6.1.2
 字段信息 124

6.1.3
 方法信息 125

6.1.4
 其他信息 127

6.2
 运行时常量池 127

6.2.1
 类符号引用 129

6.2.2
 字段符号引用 130

6.2.3
 方法符号引用 132

6.2.4
 接口方法符号引用 132

6.3
 类加载器 133

6.3.1
 readClass() 134

6.3.2
 defineClass() 135

6.3.3
 link() 136

6.4
 对象、实例变量和类变量 136

6.5
 类和字段符号引用解析 141

6.5.1
 类符号引用解析 141

6.5.2
 字段符号引用解析 142

6.6
 类和对象相关指令 144

6.6.1
 new指令 144

6.6.2
 putstaticgetstatic指令 146

6.6.3
 putfieldgetfield指令 148

6.6.4
 instanceofcheckcast指令 150

6.6.5
 ldc指令 154

6.7
 测试本章代码 156

6.8
 本章小结 160

7章 方法调用和返回 161

7.1
 方法调用概述 161

7.2
 解析方法符号引用 163

7.2.1
 非接口方法符号引用 163

7.2.2
 接口方法符号引用 165

7.3
 方法调用和参数传递 166

7.4
 返回指令 169

7.5
 方法调用指令 170

7.5.1
 invokestatic指令 170

7.5.2
 invokespecial指令 170

7.5.3
 invokevirtual指令 172

7.5.4
 invokeinterface指令 174

7.6
 改进解释器 176

7.7
 测试方法调用 178

7.8
 类初始化 181

7.9
 本章小结 185

8章 数组和字符串 187

8.1
 数组概述 187

8.2
 数组实现 188

8.2.1
 数组对象 188

8.2.2
 数组类 190

8.2.3
 加载数组类 191

8.3
 数组相关指令 191

8.3.1
 newarray指令 192

8.3.2
 anewarray指令 194

8.3.3
 arraylength指令 195

8.3.4
 aload指令 196

8.3.5
 astore指令 197

8.3.6
 multianewarray指令 198

8.3.7
 完善instanceofcheckcast指令 201

8.4
 测试数组 203

8.5
 字符串 204

8.5.1
 字符串池 205

8.5.2
 完善ldc指令 206

8.5.3
 完善类加载器 207

8.6
 测试字符串 207

8.7
 本章小结 210

9章 本地方法调用 211

9.1
 注册和查找本地方法 212

9.2
 调用本地方法 213

9.3
 反射 215

9.3.1
 类和对象之间的关系 215

9.3.2
 修改类加载器 217

9.3.3
 基本类型的类 219

9.3.4
 修改ldc指令 220

9.3.5
 通过反射获取类名 221

9.3.6
 测试本节代码 224

9.4
 字符串拼接和String.intern()方法 225

9.4.1
 Java类库 225

9.4.2
 System.arraycopy()方法 227

9.4.3
 Float. floatToRawIntBits()Double.doubleToRawLongBits()方法 229

9.4.4
 String.intern()方法 229

9.4.5
 测试本节代码 230

9.5
 Object.hashCode()equals()toString() 231

9.6
 Object.clone() 233

9.7
 自动装箱和拆箱 235

9.8
 本章小结 238

10章 异常处理 239

10.1
 异常处理概述 239

10.2
 异常抛出 240

10.3
 异常处理表 241

10.4
 实现athrow指令 245

10.5
 Java虚拟机栈信息 248

10.6
 测试本章代码 251

10.7
 本章小结 252

11章 结束 253

11.1
 System类是如何被初始化的 253

11.2
 初始化System 255

11.3
 System.out.println()是如何工作的 258

11.4
 测试本章代码 260

11.5
 总结 260

附录 指令表 263

 

前 言

Preface 前  言为什么编写本书Java语言于1995年首次公开发布,很快便取得了巨大的成功,成为使用最为广泛的编程语言之一。到现在,Java已经经历了20多个年头。在这期间,无论是Java语言本身还是Java虚拟机技术,都取得了长足的进步。现如今,Java依然长期占据TIOBE网站的编程语言排行榜首。最近更是被TIOBE选为2015年度编程语言,风采可谓不减当年。

   
众所周知,Java早已不仅仅是一个单纯的语言,而是一个开放的平台。活跃在这个平台之上的编程语言除了Java之外,还有GroovyScalaClojureJythonJRuby等。Java虚拟机则是支持这个平台的基石。

   
市面上教授Java语言的书籍种类繁多,相比之下,介绍Java虚拟机的书籍却是凤毛麟角。这足以说明Java作为一门高级语言是多么成功(让程序员远离底层),但并不代表Java虚拟机技术不重要。恰恰相反,当Java语言掌握到一定程度时,Java虚拟机原理自然就会成为必须越过的一道鸿沟。

   
近几年,国内涌现出了一些讨论Java虚拟机技术的优秀书籍,这些书籍主要以分析OpenJDKOracle JDK为主。本书另辟蹊径,带领读者自己动手从零开始用Go语言编写Java虚拟机。这样做好处颇多,弥补了OpenJDK等虚拟机的不足。

   
首先,OpenJDK等虚拟机实现非常复杂。对于初学者而言,很容易陷入代码的海洋和不必要的细节之中。其次,OpenJDK等虚拟机大多用C 语言编写。C 语言非常复杂,理解起来难度很大。最后,单纯阅读代码比较乏味,缺少乐趣,而脱离代码又很难透彻讨论技术。通过自己动手编写代码,很好地避免了上述问题。看着自己实现的Java虚拟机功能逐渐增强,看到可以运行的Java程序越来越复杂,成就感非常强。总之,通过实践的方式,相信读者可以更深刻地领悟Java虚拟机的工作原理。

    Go
Google公司于2012年推出的系统编程语言。从到硬件的距离来看,Go语言介于CJava之间。Go的语法和C类似,但更加简洁,因此很容易学习。Go语言内置了丰富的基本数据类型,并且支持结构体,所以很适合用来实现Java虚拟机。Go支持指针,但并不支持指针运算,因此用Go编写的代码要比C代码更加安全。此外,Go还支持垃圾回收和接口等Java类语言中才有的功能,大大降低了实现Java虚拟机的难度。

   
以上是本书采用Go语言编写Java虚拟机的原因,希望读者在学习本书的过程中,可以喜欢上Go这门还很年轻的语言。

   
本书主要内容全书一共分为11章,各章内容安排如下:

   
1章:安装开发环境,讨论java命令,并编写一个类似Java的命令行程序。

   
2章:讨论Java虚拟机如何搜索class文件,实现类路径。

   
3章:讨论class文件结构,实现class文件解析。

   
4章:讨论运行时数据区,实现线程私有的运行时数据区,包括线程、Java虚拟机栈、栈帧、操作数栈和局部变量表等。

   
5章:讨论Java虚拟机指令集和解释器,实现解释器和150余条指令。

   
6章:讨论类、对象以及线程共享的运行时数据区,实现类加载器、方法区以及部分引用类指令。

   
7章:讨论方法调用和返回,实现方法调用和返回指令。

   
8章:讨论数组和字符串,实现数组相关指令和字符串池。

   
9章:讨论本地方法调用,实现Object.hashCode()等本地方法。

   
10章:讨论异常处理机制,实现athrow指令。

   
11章:讨论System类的初始化过程和System.out.println()的工作原理等,并对全书进行总结。

   
本书面向读者本书主要面向有一定经验的Java程序员,但任何对Java虚拟机工作原理感兴趣的读者都可以从本书获益。如前所述,本书将使用Go语言实现Java虚拟机。书中会简要介绍Go语言的部分语法以及与Java语言的区别,但不会深入讨论。由于Go语言相对比较简单,相信任何有C系列语言(如CC C#Objective-CJava等)经验的读者都可以轻松读懂书中的源代码。

   
如何阅读本书本书代码经过精心调整,每一章(第1章除外)都建立在前一章的基础上,但每一章又都可以单独编译和运行。本书内容主要围绕代码对Java虚拟机展开讨论。读者可以从第1章开始,按顺序阅读本书并运行每一章的源代码,也可以直接跳到感兴趣的章节阅读,必要时再阅读其他章节。

   
参考资料本书主要参考了下面这些资料:

   
Java虚拟机规范》第8版《Java语言规范》第8版《深入Java虚拟机》(原书第2版)其中《Java虚拟机规范》主要参考了第8版,但同时也参考了第7版和更老的版本。《Java语言规范》则主要参考了第8版。读者可以从http://docs.oracle.com/javase/specs/index.html获取各个版本的《Java虚拟机规范》和《Java语言规范》。

   
笔者早在十年前还在上学时就读过由Bill Venners著,曹晓钢等翻译的《深入Java虚拟机(原书第2版)》。但是由于当时水平有限,理解得并不是很深入。时隔十年,重读此书还是颇有收获。较之《Java虚拟机规范》的严谨和刻板,该书更加通俗易懂。原书作者已经将部分章节放于网上,网址是http://www.artima.com/insidejvm/ed2/,读者可以免费阅读。

   
以上是Java方面的资料。Go语言方面主要参考了Go官网上的各种资料,包括《如何编写Go程序》《Effective Go》《Go语言规范》以及Go标准库文档等。另外,在本书的写作过程中,笔者还通过搜索引擎查阅了遍布于网络上(特别是StackOverflowWikipedia)的各种资料,这里就不一一罗列了。

   
下载本书源代码本书源代码可以从https://github.com/zxh0/jvmgo-book获取。代码分为GoJava两部分,目录结构如下:

    https://github.com/zxh0/jvmgo-book/v1/code/|-go|-src|-jvmgo|-java|-exampleGo
语言部分是Java虚拟机代码,每章为一个子目录,可以独立编译和运行。Java语言部分是Java示例代码,每章为一个包。Java代码按照Gradle工程标准目录结构组织,可以用Gradle编译整个工程,也可以用javac分别编译每个文件。

   
勘误和支持《Java虚拟机规范》对Java虚拟机的工作机制有十分严谨的描述。但是由于笔者水平和表达能力有限,本书一定存在表述不精确、不准确,甚至不正确的地方。另外,由于时间有限,书中也难免会有一些疏漏之处,还请读者谅解。

   
本书的勘误将通过https://github.com/zxh0/jvmgo-book/blob/master/v1/errata.md发布和更新。如果读者发现书中的错误、有改进意见,或者有任何问题需要讨论,都可以在本书的Github项目上创建Issue。此外也可以加入QQ群(470333113)与读者交流。

   
致谢首先要感谢我的家人和朋友,没有你们的鼓励、支持和帮助,本书不可能面世。这里特别感谢我的妻子,在我陷入低谷的时候,叮嘱我继续努力不要放弃。还有我的朋友范森,每章开头的可爱鼹鼠就是出自他手,希望这些鼹鼠能给枯燥的文字增添一些色彩。

   
其次感谢我所在的公司乐元素,它为我提供了舒适和愉悦的工作环境,使我在工作之余可以全心投入本书的写作之中。

   
代码被我放到了Github上,地址是https://github.com/zxh0/jvm.go。不过由于能力和时间有限,这个虚拟机离完整实现《Java虚拟机规范》还相距甚远。20154月份,我停止了jvm.go的编写,同时开始改造代码,酝酿本书。感谢所有关注过jvm.go项目的人,没有你们的帮助就没有jvm.go,也就没有本书。

   
最后,感谢机械工业出版社华章分社的编辑,本书能够顺利出版离不开他们的敬业精神和一丝不苟的工作态度。

 

媒体评论

想要了解Java虚拟机的内部运行原理,阅读虚拟机规范、书籍、源码是一种常见的途径,而从零开始自己动手编写一个实验室性质的Java虚拟机,也许会是一种更加有趣且有效的学习路径。如果不考虑Java庞大类库的实现和JVM的实际生产力需求,仅是去“正确地”实现一台Java虚拟机,其实并不如大多数人所想的那样高深和困难——只需正确读取Class文件中每一条字节码指令,并且能正确执行这些指令所蕴含的操作即可。通过本书,您可以跟随作者的思路和指引,一步步完成Java虚拟机的各个组成部分,在动手的过程中了解Java虚拟机的运作原理。
—— 周志明 《深入理解Java虚拟机:JVM高级特性与*实践》 作者

这是国内第一本以实战模式描述JVM原理的书!秀宏对JVM进行了大量研究,在书中深入浅出地分析了class文件的数据结构和JVM的基本原理,并使用Go语言用不到1万行的程序代码就实现了JVM的基本模型,是Java爱好者了解JVM实现原理的一本好书。实战才是最有效的掌握知识的手段,快快动手,实现属于自己的Java虚拟机吧!
—— 凌聪 乐元素CTO

JVM对大多数的Java开发人员,无论是初出茅庐的菜鸟以及工作多年的老手,可能都还是一个神秘的、高深莫测的黑匣子。本书的出版,使作者通过一个个实践的方式,一步步带领大家饶有趣味地揭开JVM的神秘面纱,极大加深程序员对Java的理解,进而构建更加合理高效的代码。
—— 金智伟 钱咸升(北京)网络科技股份公司CTO

返回顶部
顶部