主流JVM的组成分析

      • JVM概念
      • JVM分类
      • JVM组成
        • ClassLoader
        • Native Interface
        • Execution Engine
        • Runtime Data Area

JVM概念

VM是虚拟机,也是一种规范,他遵循着冯·诺依曼体系结构的设计原理。冯·诺依曼体系结构中,指出计算机处理的数据和指令都是二进制数,采用存储程序方式不加区分的存储在同一个存储器里,并且顺序执行,指令由操作码和地址码组成,操作码决定了操作类型和所操作的数的数字类型,地址码则指出地址码和操作数。从dos到window8,从unix到ubuntu和CentOS,还有MAC OS等等,不同的操作系统指令集以及数据结构都有着差异,而JVM通过在操作系统上建立虚拟机,自己定义出来的一套统一的数据结构和操作指令,把同一套语言翻译给各大主流的操作系统,实现了跨平台运行,可以说JVM是java的核心,是java可以一次编译到处运行的本质所在。

JVM分类

参照wikipedia,文中分的比较细,这里按照使用场景按照流行程度给出比较。
1. HotSpot VM
2. J9 VM
3. Zing VM

从 Java SE 7开始,HotSpot VM 就是Java的RI(Reference Implemention), Oracle/Sun JDK和OpenJDK都使用HotSPot VM的相同核心。
JDK8的HotSpot VM结合了JRockit VM,把功能整合实现了,比如移除了PermGen、Jcmd等部分。
J9是IBM开发的高度模块化的JVM,由于许可证限制,J9只能和IBM其他产品捆绑使用,比如Rational、WebSphere就是使用了J9。此外,J9还用在IBM在其捆绑销售的硬件上。J9总体和HotSpot VM 性能差不多,但J9比HotSpot VM 对支持一些功能,比如AOT(Ahead-Of-Time)编译,关于JIT(Just-In-Time)编译与AOT编译的比较,可以参考2。
Zing VM
应该说是最棒的JVM了吧,由Azul Systems主导,这是一家专门致力于高性能、可管理的Java及JVM系统的公司。它以Sun的HotSpot VM为基础,改进了许多会影响延迟的细节。最大的三个卖点是:(1) 低延迟、“无暂停”(pauseless)的C4 GC,GC带来的暂停可以控制在10ms以下的级别,支持的Java堆大小可以到1TB(2016年更新:目前已经支持到2TB的Java堆啦);(2) 启动后快速预热功能;(3) 可管理性:零开销、可在生产环境全时开启的、整合在JVM内的监控工具Zing Vision。目前国内有些公司也在搞JVM监控系统,看来还是就有市场前景的。

JVM组成

主流JVM的组成分析_第1张图片
这里按照主流的HotSpot VM ,画了张JVM组成图,主要4大部分组成:ClassLoader,Runtime Data Area,Execution Engine,Native Interface。

ClassLoader

ClassLoader应该很熟悉,java类里面有个getClassLoader()拿到的就是默认加载器,负责加载class文件,class文件在文件开头有特定的文件标示,并且ClassLoader只负责class文件的加载,至于它是否可以运行,则由Execution Engine决定。

Native Interface

Native Interface是负责调用本地接口的。他的作用是调用不同语言的接口给JAVA用,他会在Native Method Stack中记录对应的本地方法,然后调用该方法时就通过Execution Engine加载对应的本地lib。原本多于用一些专业领域,如JAVA驱动,地图制作引擎等,现在关于这种本地方法接口的调用已经被类似于Socket通信,WebService等方式取代。

Execution Engine

Execution Engine是执行引擎,负责给操作系统解释放入Runtime DataArea的指令和数据。

Runtime Data Area

Runtime Data Area则是存放数据的,分为五部分:Stack,Heap,Method Area,PC Register,Native Method Stack。几乎所有的关于java内存方面的问题,都是集中在这块。
1. Stack
Stack是栈内存,用来存放StackFrame,每个线程都拥有自己的栈。StackFrame包含三类信息:局部变量,执行环境,操作数栈。局部变量用来存储一个类的方法中所用到的局部变量。执行环境用于保存解析器对于java字节码进行解释过程中需要的信息,包括:上次调用的方法、局部变量指针和操作数栈的栈顶和栈底指针。操作数栈用于存储运算所需要的操作数和结果。StackFrame在方法被调用时创建,在某个线程中,某个时间点上,只有一个框架是活跃的,该框架被称为Current Frame,而框架中的方法被称为Current Method,其中定义的类为Current Class。局部变量和操作数栈上的操作总是引用当前框架。当Stack Frame中方法被执行完之后,或者调用别的StackFrame中的方法时,则当前栈变为另外一个StackFrame。Stack的大小是由两种类型,固定和动态的,动态类型的栈可以按照线程的需要分配6。
2. Native Method Stack
Native Method Stack是供本地方法(非java)使用的栈。每个线程持有一个Native Method Stack。
3. Heap
Heap是用来存放对象信息的,和Stack不同,Stack代表着一种运行时的状态。换句话说,栈是运行时单位,解决程序该如何执行的问题,而堆是存储的单位,解决数据存储的问题。Heap是伴随着JVM的启动而创建,负责存储所有对象实例和数组的。堆的存储空间和栈一样是不需要连续的,它分为Young Generation和Old Generation(也叫Tenured Generation)两大部分。Young Generation分为Eden和Survivor,Survivor又分为From Space和 ToSpace。和Heap经常一起提及的概念是PermanentSpace,它是用来加载类对象的专门的内存区,是非堆内存,和Heap一起组成JAVA内存,它包含MethodArea区(在没有CodeCache的HotSpotJVM实现里,则MethodArea就相当于GenerationSpace)。在JVM初始化的时候,我们可以通过参数来分别指定,PermanentSpace的大小、堆的大小、以及Young Generation和Old Generation的比值、Eden区和From Space的比值,从而来细粒度的适应不同JAVA应用的内存需求。
图中 Eden区里面存着是新生的对象,From Space和To Space中存放着是每次垃圾回收后存活下来的对象 ,所以每次垃圾回收后,Eden区会被清空。 存活下来的对象先是放到From Space,当From Space满了之后移动到To Space。当To Space满了之后移动到Old Space。Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor复制过来的对象。而且,Survivor区总有一个是空的。同时,根据程序需要,Survivor区是可以配置为多个的(多于两个),这样可以增加对象在年轻代中的存在时间,减少被放到年老代的可能。Old Space中则存放生命周期比较长的对象,而且有些比较大的新生对象也放在Old Space中。
Method Area在HotSpot JVM的实现中属于非堆区,非堆区包括两部分:Permanet Generation和Code Cache,而Method Area属于Permanert Generation的一部分。Permanent Generation用来存储类信息,比如说:class definitions,structures,methods, field, method (data and code) 和 constants。Code Cache用来存储Compiled Code,即编译好的本地代码。
4. PC Register
PC Register是程序计数寄存器,每个JAVA线程都有一个单独的PC Register,他是一个指针,由Execution Engine读取下一条指令。如果该线程正在执行java方法,则PC Register存储的是 正在被执行的指令的地址,如果是本地方法,PC Register的值没有定义。PC寄存器非常小,只占用一个字宽,可以持有一个returnAdress或者特定平台的一个指针。
5. Method Area
Method Area在HotSpot JVM的实现中属于非堆区,非堆区包括两部分:Permanet Generation和Code Cache,而Method Area属于Permanert Generation的一部分。Permanent Generation用来存储类信息,比如说:class definitions,structures,methods, field, method (data and code) 和 constants。Code Cache用来存储Compiled Code,即编译好的本地代码,在HotSpot JVM中通过JIT(Just In Time) Compiler生成,JIT是即时编译器,他是为了提高指令的执行效率,把字节码文件编译成本地机器代码。

你可能感兴趣的:(java基础)