节选自:http://www.cubrid.org/blog/dev-platform/understanding-jvm-internals/
一、 JVM特性
1、 简介
1、虚拟机栈:最流行的计算机架构比如intel x86架构和arm架构都是基于寄存器运行的,然而,jvm是基于栈运行的
2、符号引用:所有的类型(类和接口)除了原始类型(即基本类型)都是被符号引用所引用的,代替显示的通过内存地址引用
译者注:符号引用即变量
3、GC垃圾回收:一个类实例通过用户代码显示的创建,而通过GC自动回收,不用手动干预。
4、基本数据类型平台独立:传统的编程语言比如c++根据不同的平台有不同的int类型内存大小,而jvm显示的定义了基本数据类型的内存大小,跟平台是无关的。
5、网络字节序:java类文件使用的时候网络字节序。为的是保持平台无关性:Intel x86架构使用的是小端字节序,而RISC 系列架构使用的大端字节序,所有一个固定的字节序必须被保持。jvm使用的网络字节序是被用于网络传输的。网络字节序是大端字节序。
虽然java 是sun公司开发的,但是任何的供应商只要遵循jvm规范,都可以开发和提供jvm虚拟机。正因为这个原因,有各种各样的jvm,包括oracle Hotspot jvm 和IBM JVM。Google的安卓系统上的Dalvik VM也是JVM中的一种,但是它没有遵循JVM规范。不同于java VMs的虚拟机栈,Dalvik VM是基于寄存器架构的。Dalvik VM会将java字节码转换成基于寄存器的指令集。
2、 Java字节码
为了实现平台无关性,JVM使用java字节码,java字节码是处于java(用户语言)和机器语言的一种中间语言,java字节码是发布java代码最小的单元。
在解释java字节码之前,让我们先来看看它,这个列子是发生在开发进程中的真实列子的总结。
二、 JVM结构
1、 执行流程
java代码是按照下图所示的流程执行的
类加载器将javac编译的java字节码加载进运行时数据区;而执行机则执行java字节码
2、 类加载器
java提供了动态加载特性;类加载器是在运行时而不是编译时,将加载和链接它所引用到的类。JVM的类加载器执行这个动态加载。
类加载器具有如下这些特性:
1、分层结构:类加载器是以父子关系组成的一个分层结构,Bootstrap 加载器是所有加载器的父类。
2、委托模式:基于这个分层结构,类加载器之间是委托加载的。当一个类加载的时候,这个父类加载器将被检查来确定这个类是否在这个父类加载器中,如果父类加载器已经有了这个类,则直接使用,否则,这个类加载器将加载这个类。
3、可见性:一个子类加载器可以找到父类加载器中的类,但是,一个父子类加载器不能找到子类加载器中的类。
4、不能卸载:一个类加载器可以加载类但是不能卸载类,代替卸载的是,这个类加载器可以被删除,然后重新创建一个类加载器。
每一个类加载器有自己的名字空间用来存储加载的类。当一个类加载器加载一个类时,它根据FQCN (全类名匹配)在存储在名字空间中的类来搜索类,并且检查其是否已经被加载过了。如果一个类有相同的名字但是在不同的名字空间,类加载器会认为它是一个不同的类。如图
3、 运行时数据区
运行时数据区是一个内存区域,是在JVM程序在操作系统上运行时分配的。这个运行时区分为6个区域:
- 线程私有:PC寄存器(程序计数器),JVM栈,本地方法栈
- 线程共享:堆,方法区,运行时常量池
1、PC寄存器:又叫程序计数器,存在于每一个线程中,在线程开始的时候被创建,它存储正在被执行的JVM指令地址
2、JVM栈:存在于每一个线程中,在线程开始的时候被创建。它是一个个结构体(栈帧)的栈空间。JVM将栈帧入栈和出栈
- 栈帧:一个栈帧当一个方法在JVM中执行的时候被创建,然后被添加进这个线程的JVM栈中。当这个方法结束的时候,这个栈帧就被移除了。每个栈帧包括本地变量组的引用,操作栈和该方法所属的类的运行时常量池。本地变量组和操作栈的大小在编译时就被确定了,因此,一个栈帧的大小是根据方法来确定的。
- 本地变量组:它的索引从0开始,0表示这个方法所属的类实例的引用,所以方法参数是从索引1开始保存在这个本地变量组中的。最后才是依次保存该方法的本地变量。
- 操作栈:表示一个方法的实际工作空间。每个方法在操作栈和本地变量组之间交换数据。对其他方法的调用结果进行出栈和入栈。操作栈所需要的空间在编译时就被确定了。
3、本地方法栈:表示其他语言(非java)写的本地代码栈。换句话说,它是一个被JNI调用的C/C++代码执行时使用的栈空间。
4、方法区:这个方法区被所有的线程共享。当JVM开始的时候被创建。它存储运行时常量池,域和方法信息,静态变量和被JVM读取的每个类和接口的方法字节码。方法区根据不同的JVM供应商而被实现为了不同的格式。Oracle Hotspot JVM 叫它永生代。对于每个JVM供应商,这个方法区对于GC是可选的。
5、运行时常量池:这个区域包含在方法区中,它是JVM操作中的一个很核心的角色。因此,JVM规范分开描述了它的重要性。包含了每个类和接口的常量,方法和域的引用。简单的说,当一个方法和域被引用的时候,JVM搜索这个方法和域在运行时常量池中的实际的地址
6、堆:存储实例和对象的一个空间。是GC的一个操作目标。这个空间在讨论JVM性能的时候被经常提到。这JVM供应商能确定这个堆怎么配置或者不被回收。