JVM包含两个子系统和两个组件
类装载子系统(Class loader)
根据给定的全限定名称将class文件加载到JVM内存,转为Class对象
运行时数据区(Runtime data area)
即JVM的内存
执行引擎 (Exception engine)
也叫解释器,负责解释命令,交由操作系统执行。执行classes中的指令
本地库接口 (Native Interface)
本地接口的作用是融合不同的语言为java,所用是其他编程语言交互的接口
运行流程
(1)首先通过编译器把Java代码转换为字节码,类加载器(Class loader)再把字节码加载到内存中,将其放在运行时数据区(Runtime data area)的方法区中
(2)然后使用特定的命令解析器执行引擎 (Exception engine),将字节码翻译成底层系统指令。因为字节码文件只是JVM的一套指令集规范,并不能直接交给底层操作系统去执行,因此需要特定的命令解析器执行引擎将字节码翻译成底层系统指令。
(3)再将底层系统指令交由CPU去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能。
1 类装载子系统
1.1 四种类加载器
启动类加载器 (Bootstrap 类加载器)
加载$JAVA_HOME/jre/lib/rt.jar里所有的class,不是ClassLoader子类
扩展类加载器 (Extension 类加载器)
加载java平台中扩展功能的一些jar包,包括SJAVA_HOME/jre/lib/* .jar
或-Djava.ext.dirs指定目录下的jar包
应用程序类加载器 (Application 类加载器)
加载classpath中指定的jar包及目录中class
Custom自定义类加载器
应用程序根据自身需要自定义的ClassLoader,如ltomcat、jboss都会根据j2ee规范自行实现ClassLoader。
1.2 类装载的执行过程
加载:根据查找路径找到相应的class文件然后导入
验证:字节码校验器会检生成的字节码是否正确,如果验证失败则会验证错误
准备:对于所有静态变量的内存分配和默认值分配
识别:解析或识别是从运行时常量池的符号引用中动态具体值的过程
初始化:类或接口的初始化由执行类或接口初始化方法构成。这里所有的静态变量与原来的值将被指派,静态块将被执行
2 运行时数据区
结构图如下:
方法区(Method Area)
存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
堆(Head 堆)
在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
存储的数据不是线程安全的,堆和常量空间不足则会引发OutOfMemoryError
虚拟机栈(VM Statck)
每一个线程创建一个单独的运行时堆栈。对于每一个方法调用,一个称为栈内存栈帧被创建,所有局部变量将被创建在栈内存中。栈区域是线程安全的,因为它不是一个共享资源。
与程序计数器一样,JVM栈也是线程私有的,它的生命周期与线程相同。
栈空间用光了会引发StackOverflowError
本地方法栈(Native Method Stack)
与虚拟机栈的作用是一样的,只不过虚拟机栈是服务java方法的,而本地方法栈是为虚拟机使用的 Native 方法服务
程序计数器(Program Counter Register)
每个线程必须分开程序计数器登记,当前执行的指令一旦执行,程序计数器(程序计数登记器)更新下一个指令。一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。
3 执行引擎 (Exception engine)
通过类装载器装载的,被分配到VM的运行时数据区的字节码会被执行引擎执行。执行引擎以指令为单位读取Java字节码。它就像一个CPU一样,一条一条地执行机器指令。每个字节码指令都由一个1字节的操作码和附加的操作数组成。执行引擎取得个操作码,然后根据操作数来执行任务,完成后就继续执行下一条操作码。