首页 > 学院 > 开发设计 > 正文

JVM运行数据环境

2019-11-10 19:34:50
字体:
来源:转载
供稿:网友

JVM(java virual machine)Java虚拟机是Java语言的基础,虽然名称叫做java虚拟机,但是跟Java语言并没有强相关,JVM主要提供一种执行字节码(class文件的载体),很多其他的语言例如python都有基于jvm的实现版本,JVM在很多时候给我们提供了便利,屏蔽了很多细节,尤其是垃圾回收与跨平台与多线程机制.

JVM的基本结构如下: 这里写图片描述

它处于连接基本类库与字节码文件和操作系统之间的位置.jvm也是Java语言跨平台的基础.

Java整个语言体系如图:

这里写图片描述

jdk中的jre首先用编译器讲我们编写的Java文件编译成class字节码文件,然后JVM加载字节码文件进行解释执行.不针对特定平台进行编程,因为每个平台都应该应该依赖JVM规范进行JVM实现.因此抽象出的公共接口暴露给程序调用的规范是统一的.

这里写图片描述

前面也提过,JVM并不认识特定的语言,而是只认识字节码文件,JVM规范对字节码文件格式进行严格的控制,这直接关系到JVM的安全性.依照特定的规则在执行引擎的处理下,JVM完成类加载,将静态的类文件映射到虚拟机的运行数据环境.

类加载如下:

这里写图片描述

到了运行数据区,这里就是JVM进行管理的主要内存区域了,这里主要分为6个部分:程序计数器,虚拟机栈区,本地方法栈区,堆区,方法区,运行时常量池.

主要结构如图: 这里写图片描述 接下来分别介绍6个数据区的主要用途:

1. 程序计数器

程序计数器占用的大小比较小,每个线程都会创建自己的程序计数器,当然它的生存周期也就跟线程的生存周期保持一直了,它的主要用途是跟踪程序方法执行的路径,它记录了当前方法执行的操作和位置,在进行多线程调度的时候是需要进行CPU分片的,有了程序计数器就可以保护线程的执行情况,当获得CPU使用权的时候能够进行线程恢复.它一般存放的指令为:分支、循环、跳转、异常处理等指令.如果是不是本地方法,这里存放就是字节码指令的地址,如果是本地方法,它的值是undefined.这个区域通常来说比较小,也是JVM唯一没有规定OutOfMemoryError的区域.

2.虚拟机栈区

 这个区域也是线程私有的区域,当每个方法进行执行的时候都会在栈区创建栈帧(stack frame),栈帧一般存放的局部变量表,操作数栈,动态连接与方法出口等信息.局部变量表存放的方法入口还有在编译器就确定的基本数据类型(long与double类型占用两个slot,其余占用一个)和引用类型和returnAddress类型(eturnAddress类型会被Java虚拟机的jsr、ret和jsr_w指令所使用。returnAddress类型的值指向一条虚拟机指令的操作码。与前面介绍的那些数值类的原生类型不同,returnAddress类型在Java语言之中并不存在相应的类型,也无法在程序运行期间更改returnAddress类型的值。)这个区域确定了两种异常情况,当方法调用深度超过JVM的允许值会抛出StackOverflow,如果动态的扩展无法申请到足够多的内存也会抛出OutOfMemoryError,虚拟机规范并没要求这个区域是否可扩展,但大部分实现的虚拟都是可扩展的.

3.本地方法栈

 本地方法栈与虚拟机栈基本一直,主要区别一个管理的目标是字节码定义的方法栈,本地方法栈管理的是本地方法.这个区域的规范并不强制语言与数据结构,给跨平台提供灵活的选择性.

4.堆

 这是虚拟机中最大的一块区域,也是开发者所指的JVM内存的主要含义,不仅仅是因为它所占比例一般最大,更重要的是垃圾回收的目标也主要在这个区域,这个区按照规范的定义是存放实例的唯一区域,但是随着最新的技术发展(JIT技术与逃逸)发展,对象也不一定在这个区域存放.这个区域也是多个线程共享的,因此也会带来多线程并发的复杂性.保持对象的一致性也是控制堆上的对象能够对多个线程保持数据的一致.堆上主要存放对象实例和数组,当JVM启动的时候就存在了堆区域,这与栈区不太一样,栈是在方法开始调用的时候才开始创建.堆中的垃圾回收根据对象生存周期的不同来进行分代收集,主要的收集算法也有标记-清除,复制-整理,复制-压缩等算法,根据这些算法也有一些串行,并行,甚至并发的垃圾收集器.在主流hotspot也分为年轻代(可以分为Eden和Survivor)和老年代.这个区域可以是连续的内存也可以只是逻辑连续的.

5.方法区

 这个区域主要存放被JVM加载的类的信息,包括常量,静态变量,即时编译后的代码,这个区域垃圾回收效果收益不大但是是必要的.主要的收集对象为常量和需要卸载的类,类的回收机制有特定的要求.,并且十分的严苛.这个区域别名为Non-heap.在hotspot中使用堆中的永久区(其他JVM实现一般没所谓的永久区)来实现方法区,这样将垃圾回收器直接覆盖到了堆中的方法区(hotspot中的永久区),省去了专门为永久区进行垃圾收集的工作,但是这样增加了堆溢出的风险,因此现在jdk逐渐讲方法区移除到堆外.

6.运行时常量池

 属于方法区的一个部分,存放Class类编译器各种能够确定的字面量和符号引用(和直接引用).字节码格式中一般对其他区域要求严格,这个区域是比较宽松的.受到方法区大小限制,申请不到足够的内存也会抛出OutOfMemoryError异常.

7.堆外内存(直接内存)

 有些时候我们可以直接使用堆外内存,例如jdk1.4引入的java nio就用channel与buffer调用本地方法在堆外分配内存,使用堆上的DirectByteBuffer作为引用进行操作,这样减少了堆内外数据交换,提升性能.当然这个区域的大小受到物理内存大小限制,申请不够抛出OutOfMemoryError异常.


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表