1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > Java虚拟机及运行时数据区

Java虚拟机及运行时数据区

时间:2018-05-10 18:27:04

相关推荐

Java虚拟机及运行时数据区

1、JVM定义

Java虚拟机(Java Virtual Machine),简称JVM。当我们说起Java虚拟机时,可能指的是如下三种不同的东西:

抽象的虚拟机规范规范的具体实现一个运行中的虚拟机实例

Java虚拟机抽象规范仅仅是一个概念,在《The Java Virtual Machine Specification》中有详细的描述。

该规范的实现,可能来自多个提供商,并存在于多个平台上,它或者是全部由软件实现,或者是以硬件和软件相结合的方式来实现。JVM的实现有很多,广为使用的主要有三个(由于Sun和BEA被Oracle收购,故HotSpot、JRockit已都为Oracle所有):

Sun HotSpot(服务端、桌面、嵌入式 通用)BEA JRockit(专注于服务端)IBM J9(服务端、桌面、嵌入式 通用)

当运行一个Java程序的时候,也就在运行一个Java虚拟机实例。注意,我们所说的Java平台无关性是指class文件的平台无关性,JVM是和平台相关的,不同操作系统对应不同的JVM。

2、JVM架构

HotSpot虚拟机是官方的、最常用的JVM规范实现,这里以HotSpot虚拟机为例。

2.1、HotSpot JVM架构

如图,JVM可以分为三部分:类加载子系统、运行时数据区、执行引擎。

(图片来源:Java Garbage Collection Introduction)

更详细的结构:

(图片来源:The JVM Architecture Explained)

2.2、HotSpot JVM在Java SE中的位置

(图片来源:Jave SE Platform at a Glance)

3、JVM运行时数据区

JVM规范定义了若干种程序运行时使用到的运行时数据区:

分为两种,一种随虚拟机的启动和退出而创建和销毁(方法区、堆),一种随线程的开始和结束而创建和销毁(虚拟机栈、本地方法栈、程序计数器):

方法区:类信息(版本、字段、方法、接口等描述信息,类的Class对象也存在此)、常量、静态变量、即时编译后的代码、运行时常量池(存放编译器生成的字面量和符号引用)等。(OutOfMemoryError异常)堆:实例对象(及数组)。注意不是所有对象,如上面所说类的Class对象存放在方法区。(OutOfMemoryError异常)栈(HotSpot对虚拟机栈和本地方法栈不加以分区,二者合二为一)::存放线程执行产生的栈帧信息(OutOfMemoryError异常、StackOverFlow异常) 虚拟机栈(线程栈): 局部变量表(编译期可知的基本数据类型、引用类型、returnAddress)、操作数栈、动态链接、方法出口信息等本地方法栈:与虚拟机栈类似程序计数器:所属线程下一条要执行的指令的地址。(没有规定异常)

方法区、堆区、栈区 均可实现成固定大小容量或实现成可动态扩展容量的。

3.1、程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看做是当前线程所执行的字节码的信号指示器。若线程正在执行的是一个Java方法,则程序计数器保存的是当前所在线程下一条要执行的字节码指令的地址;若正在执行的是Native方法,则计数器值为空(undefined)。

线程私有,每个JVM线程都有自己的程序寄存器。

此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

3.2、Java虚拟机栈

Java虚拟机栈(Java Virtual Machine Stack)即线程运行栈,描述的是Java方法执行的内存模型:每个方法被执行时会同时创建一个栈帧(Stack Frame)用于局部变量表(存编译期可知的基本数据类型、引用类型、returnAddress)、操作数栈、动态链表、方法出口信息等。每一个方法被调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。

线程私有,每一个JVM线程都有自己的java虚拟机栈,这个栈与线程同时创建,它的生命周期与线程相同

JVM stack可以实现成固定大小,也可以实现成可动态扩展的。若实现成固定大小,则每一条线程的JVM Stack容量应该在线程创建时就指定了大小,JVM实现应该提供调节JVM Stack初始容量的手段;若实现成可动态扩展的方式,则应该提供调节最大、最小容量的手段。

能创建的栈的数量(即线程的数量)受所在机器物理内存的限制,但实际上OS对一个进程能使用的内存大小(Windows 2GB)是有限制的,故能创建栈的数量受OS的这个限制。换句话说,JVM并没有支持调节各栈能用的总内存而是只提供了对一个栈大小的调节。

异常(两者实际上有重叠):

StackOverflowError:纵向无法分配即无法分配新的栈帧时 抛出此异常。

OutOfMemoryError:横线无法分配即无法建立新的线程(在创建新线程时没有足够内存来创建对应的虚拟机栈时 或者 JVM Stack可以动态扩展但在尝试扩展时无法申请到足够的内存来完成扩展,也就是超过了OS对一个进程能创建的线程数的限制时)时 抛出此异常。

3.3、本地方法栈

Java虚拟机可能会使用到传统的栈来支持native方法(使用Java语言以外的其它语言编写的方法)的执行,这个栈就是本地方法栈(Native Method Stack)。

线程私有。

本地方法栈发挥的作用域Java虚拟机栈相似。有的虚拟机(如HotSpot)不对两者加以区分,合二为一。

3.4、方法区

方法区(Method Area)用于存储已被虚拟机加载的类信息(版本、字段、方法、接口等描述信息)、常量、静态变量、即时编译后的代码、运行时常量池等。

各线程共享。

方法区的容量可以实现成固定大小的,也可以实现成可动态扩展的,并在不需要过多空间时候自动收缩。

方法区可以处于物理上不连续的内存空间中,只要逻辑连续即可。

OutOfMemoryError异常: 方法区的内存空间不能满足内存分配请求,且无法扩展时抛出此异常。

运行时常量池:存放编译器生成的各种字面量和符号引用

是方法区的一部分。Class文件编译后生成的各种字面量和符号引用放在文件的常量池中,这部分内容在类加载后进入方法区的运行时常量池。

与Class文件常量池相比,运行时常量池具备动态性:不要求常量只有在编译期才能产生,即并非预置入Class文件中常量池的内容才能进入运行时常量池,运行期间也可将新常量放入运行时常量池,如String的intern()方法(见Java小记-MarchOn)。

OutOfMemoryError异常:当创建类和接口时,如果构造运行时常量池所需的内存空间超过了方法区所能提供的最大内存空间后就会抛出此异常。

注:方法区/永久代/元空间:

方法区常又被称为永久代(PermGen space)、元空间(Metaspace),它们并不等价,区别是:方法区为JVM的规范,永久代、元空间分别是方法区在HotSpot中的一种实现;对于其他类型的虚拟机实现,如 JRockit(BEA)、J9(IBM),其并没有永久代、元空间这些概念,其只要不触碰到进程可用内存上限即可。

从JDK1.7开始,逐渐开始去永久代工作:JDK1.7中,存储在永久代的部分数据就已经转移到了Java Heap或者是 Native Heap。(如符号引用(Symbols)转移到了native heap;字面量(interned strings)、类的静态变量(class statics)转移到了java heap);从JDK1.8起,改用本地内存实现方法区,称为元空间。元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制。

3.5、Java堆

Java堆是几乎所有对象(有例外,如类的Class对象置于方法区)实例分配内存的区域。堆在虚拟机启动的时候被创建,堆中储存了各种对象,这些对象被自动内存管理系统(Automatic Storage Management System,也即是常说的“Garbage Collector(垃圾回收器)”)所管理。这些对象无需、也无法显示地被销毁。

各线程共享。

堆的容量可以实现成固定大小的,也可以实现成可动态扩展的,并在不需要过多空间时候自动收缩。

Java堆可以处于物理上不连续的内存空间中,只要逻辑连续即可。

Java堆异常(OutOfMemoryError):若在堆中没有足够内存完成实例分配,并且也无法扩展时,抛出此异常。

3.6、本地直接内存(不是运行时数据区)

本地直接内存(Direct Memory)不是虚拟机运行时数据区的一部分,也不是Java虚拟机规范定义的内存区域。但也可被使用,而且也可能出现OutOfMemoryError异常。其不受堆大小的限制,但受到本机进程可用内存的限制。

4、JVM各区域内存分配参数设置

上述各区域内存大小的配置可参看HotSpot JVM各区域内存分配参数设置-MarchOn

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。