JVM架构
JVM的总体结构大致如下:
这样,其实我们就知道了JVM到底是来干什么的了。学习的时候最初也是最重要的是得明白自己要从这个里面学到什么东西,如果学习JVM的时候去把具体的实现也去看一遍,估计收获是有的,但是花的时间太长了,所以这里就止步于字节码,不会再往下深究。
这里基本上我们想象的属性全有了。常量池应该是最重要的,因为从上面可以看到下面的属性之类的都是保存其在常量池中的索引。常量池中有很多种类型,下面分别具体来看。常量池中容纳的符号引用包括三种特殊字符串:
- 全限定名:倒过来的域名用来作为类或接口的名称,唯一的。
- 简单名称:字段或方法的名称,保存的就像在Java文件中定义的。
- 描述符:给出字段的类型。
其中比较麻烦的就是描述符,对普通属性字段的描述会像[[[Z用来表示boolean[][][] isReady,而方法的描述符会像()Ljava/lang/String这样用来描述方法String toString()。
好了,现在言归正传,CONSTANT_Utf8_info表项的格式如下:
CONSTANT_Integer_info等于基本类型的表项格式如下(不同类型bytes数组的大小不同):
CONSTANT_Class_info表示了一个类型,CONSTANT_Fieldref_info结构与此类似,只是表示的类型不同而已。其实它只是保存一个类型的名称:
CONSTANT_Fieldref_info描述指向字段的符号引用,结构如下:
CONSTANT_Methodref_info,CONSTANT_InterfaceMethodref_info,CONSTANT_NameAndType_info的结构和CONSTANT_Fieldref_info的相同,关键是他们指向的地方的描述符是不同的。
好了,常量池,也就是cp_info的结构的分析就到此为止,可以看出这里面包含的只是最简单的单位,也就是用这些东西来构成更复杂的东西。下面来看字段,也就是field_info的结构。
后面method_info的结构也是这样的,只是说他的属性和表示的类型是不一样的。下面就来看具体的属性是如何表示的,同时在看的时候可以对照一下ELF文件格式,很像的样子。
到此为止,Class文件的结构就大致分析完了。
类型的定义保存在class文件中,从保存在磁盘上的文件到在Java虚拟机中能运行的类型要经历的过程就是类型的装载,大致的过程如下:
大家通常想的是如何释放不再使用的对象(也就是垃圾回收),但很少去了解类型的释放。其实在虚拟机上运行的类型占用的空间不是特别多,需不需要释放呢?类型的释放和对象的释放是一个道理:如果程序无法触及到它的时候将其释放。
这里开始介绍Java虚拟机中大名鼎鼎的垃圾回收。
这里不会详细的说明各种垃圾回收算法,大致的演化过程为:为每个对象设置一个统计变量,当统计变量为0的时候就可以回收了。但是这种方法的致命的弱点是无法处理循环引用。所以也就有了后来的按照无法触及这个概念来处理的算法。但是,这时候问题又来了,如何判断无法触及?广搜深搜都可以,但是得把程序停下来,而且效率想想也不会太高。好了,我们发现,每次都是处理所有的对象,有一些对象在程序中是比较稳定的,那他们在处理的时候被移来移去必然会浪费比较多的时间,这就导致了按时间分别处理的回收器算法。
到了最后,兼顾上面各个算法的优缺点提出了火车算法:每次考虑一个车厢,如果这个车厢里面有循环引用是没有关系的,如果外面有对车厢中对象的引用那么将对应的对象移出去。这样做的好处是垃圾回收本来是一个大的动作,但是火车算法在每次回收的时候只处理其中的一个车厢,也就是说每次的处理时间会变得很少,用户程序对这种影响几乎意识不到。
在《深入Java虚拟机》的后面一大堆都是在说命令的含义,其实感觉这个东西反而是不需要太多的看的,了解一下就可以了。