JVM-运行时数据区(Run-time Data Areas)

来源:互联网 发布:painttool sai mac 编辑:程序博客网 时间:2024/05/22 01:52

在JVM规范中,定义了以下几种运行时数据存储区:
- 程序计数器;
- java虚拟机栈;
- 本地方法栈;
- java堆;
- 方法区。

程序计数器

程序计数器是一块很小的内存空间。由于java是支持多线程的语言,当线程数量超过CPU数量时,线程之间就会根据时间片轮询来抢夺CPU资源。对于单个CPU而言,在同一时刻,只能有一个线程在执行,而其他线程则会被切换出去。因此,每个线程之间都必须有独立的程序计数器,用于存储下一条要执行的指令。程序计数器之间相互独立,互不影响,是线程私有的一块内存空间。

如果线程正在执行的是java方法,则程序计数器记录着正在运行的java方法的字节码地址;如果线程正在执行的是本地方法,则程序计数器为空。

程序计数器的容量至少应当能保存一个返回值地址或者一个与平台相关的本地指针的值

java虚拟机栈

java虚拟机栈也是线程私有的一块内存空间,它和java线程在同一时间创建,它包含有方法的局部变量和部分结果,并参与方法的调用和返回。在java虚拟机规范中,允许java虚拟机栈的空间大小可以是固定的或者是动态拓展的。在java虚拟机中规范中,定义了两种跟栈空间大小有关的异常:StackOverflowError和OutOfMemeryError。如果线程在计算过程中,申请的栈深度超过了最大的可用深度,则会抛出StackOverflowError。如果java虚拟机的栈空间大小是动态拓展的,在栈的拓展过程中,没有足够的内存空间来支持栈的拓展,则会抛出OutOfMemeryError。

虚拟机栈在运行时使用了一种叫做栈帧的数据结构来存储上下文信息。在栈帧中,存放了局部变量表、操作数栈、当前方法对应类的运行时常量池的引用和方法返回值等信息。每个方法的调用都标识着栈帧的入栈操作,相应的,每个方法的返回也标识着栈帧的出栈操作。在方法的调用过程中,如果方法的参数和局部变量数量相对较多,那么栈帧中的局部变量表也会相对较大,栈帧会膨胀以满足方法调用所需传递的信息,因此,单个方法调用所需的栈空间大小也相对较大。

栈帧除了用来存储数据之外,同时还用来处理动态链接和异常分配。

本地方法栈

本地方法栈和java虚拟机栈是功能类似的结构。java虚拟机栈管理的是java方法,而本地方法栈管理的是本地方法。本地方法是由C类语言实现,同时也有StackOverflowError和OutOfMemeryErro两种异常。

java堆

java堆是最为重要的一部分,几乎所有的对象和数组都是在堆中分配空间。java堆可分为新生代和老年代,新生代存放的刚刚产生的对象和年轻的对象,如果对象一直没有被回收,那么就会成为老年对象,老年对象就会被移入老年代。

新生代还可以细分为eden和s0/s1。eden意为对象出生地,刚刚建立的对象,通常都会存储在这个地方。s0/s1意为幸存区,这里所存储的对象至少都经历过一次垃圾回收,幸存区的对象如果到了指定年龄还未被回收,则有机会进入老年代。

方法区

方法区中存储的信息包含有类的信息、常量池、字段信息、方法信息。
- 类的信息中包含有类的修饰符、类的完整名称、父类的完整名称,直接接口的完整名称;
- 常量池包含有类的方法和字段等所引用的常量信息。
- 字段信息中包含有字段修饰符、字段类型和字段名称。
- 方法信息中包含有方法修饰符,方法返回值类型、方法名称、方法参数、方法字节码地址、方法的操作数栈、方法的局部变量表大小以及异常表。

方法区中的信息都来自于class文件,是java程序运行时必不可少的信息。

原创粉丝点击