java 运行时数据区详解

来源:互联网 发布:鲍尔州立大学 知乎 编辑:程序博客网 时间:2024/05/21 09:58

java虚拟机定义了若干java程序运行时产生的运行时数据区,他们中有一些随着程序(进程)创建而创建,另一些则跟随线程的生命周期创建和销毁,了解这些对java程序员排查outofmemoryError错误和性能优化有着非常重要的意义。

jvm运行时内存区域划分

程序计数器

java虚拟机支持多线程,在任意时刻,一个cpu核心只能够运行一条指令,为使得多线程切换后线程能够找到之前的执行状态,需要在pc中保留着进程的运行状态。当jvm执行java进程址,pc的值保存着java虚拟机正在执行的字节码指令的地址,当jvm执行的方法址native方法(即非java程序的方法)时,pc为空(undefined)。pc的容量至少能够保存一个returnAddress类型的值或者一个平台无关的本地指针的值。每一个java线程都有自己的pc,即pc时线程隔离的。

java虚拟机栈

java虚拟机栈随线程创建而创建,用于存储栈帧(Frame),包括一些局部变量和一些尚未计算好的中间结果等,所以java虚拟机栈时线程隔离的,每一个java线程都有自己的虚拟机栈。java虚拟机栈的空间可以在java堆中分配,并且不需要保证空间分配的连续性。该区域定义了StackOverflowError和OurOfMemoryError两种异常。

java堆

java虚拟机中,堆是提供各个线程共享的运行时内存区域。java堆在jvm启动是分配,它存储了呗自动内存管理系统(即GC,垃圾回收器)管理的对象。在该区域内存储的对象生命周期结束后不需要像C++程序那样显式的回收,java虚拟机会根据垃圾回收算法自动回收这部分对象所占用的内存。java堆可以在jvm启动时显示的设置固定大小,也可以根据程序需要动态的扩展,并在不需要时动态回收。java堆内存不需要保证内存的连续性。java进程在申请超过gc提供的最大内存后,会抛出OutOfMemoryError。

方法区

方法区也是jvm提供各个线程共享的运行时内存区域,方法区存储了每一个类的结构信息,包括运行时常量池、类属性、方法数据、构造函数、方法字节码信息等。方法区在jvm启动时创建,容量可固定也可按需分配回收,方法区内可以不实现垃圾回收和压缩。并且可以不保证内存区域的分配的连续性。如果内存无法分配,则抛出OutOfmemoryError异常。

运行时常量池

运行时常量池时运行时class文件中每一个类或者接口的常量池表的运行时表示形式。上一节提到常量池在方法区中分配如果常量池无法分配到所需空间,则抛出OutOfMemoryError。

本地方法栈

jvm中用于支持native方法的栈区。如果jvm不支持native方法,或者本身不依赖传统栈,则可以不分配本地方法栈。参考java虚拟机栈,本地方法栈也是线程隔离的。如果线程申请超过允许最大容量的本地方法栈,会抛出StackOverFlowError,如果系统无法提供足够的内存创建本地方法栈,则抛出OutOfMemoryError。

一些名词

栈帧(Frame)

栈帧是用来存储数据和和部分过程结果的数据结构。栈帧随方法创建而创建,随方法结束而销毁。每一个栈帧都有本地变量表和操作数以及指向当前方法所属类的运行时常量池的引用。本地变量表盒操作数栈的容量在编译期间就确定了,因此栈帧的大小取决于jvm虚拟机的具体实现。当前正在执行的方法的方法栈叫做当前栈帧,这个方法叫做当前方法,这个方法的所属类叫做当前类。

局部变量表

每一个栈帧(Frame)都包含一个局部变量表的结构。一个局部变量可以保存boolean、byte、char、short、int、float或者returnAddress类型或者reference type类型的值,long、double类型的值需要两个局部变量表示。局部变量表使用从0开始的索引进行定位。

操作数栈

每个栈帧(Frame)都包含一个叫做操作数栈的数据结构。操作数栈在栈帧创建的时候是空的,其深度在运行时决定。在方法调用时,操作数栈用来存储方法参数盒方法返回值;方法运行时,操作数栈用来存放从局部变量表或者对象实例中复制的常量变量等。操作数栈上的一个单位可以存储java虚拟机定义的任意类型数据。但是操作数栈的深度计算时,一个long或者double类型的数据会占用两个单位的栈深度(存在疑问)。

总结

从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的。