java运行时数据区

来源:互联网 发布:win10系统ps软件 编辑:程序博客网 时间:2024/06/07 18:14

根据《深入理解java虚拟机》第二章内容整理而得。

首先,贴一张结构运行时数据区结构图:


java虚拟机运行时数据区由 程序计数器、虚拟机栈、本地方法栈、堆、方法区组成。(HotSpot虚拟机并不区分虚拟机栈和本地方法栈


1.程序计数器

程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码(Java 字节码(英语:Java bytecode)是Java虚拟机执行的一种指令格式。)的行号指示器。字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。

为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各条线程之间计数器互不影响,独立存储,我们称这类内存区域为“线程私有”的内存。

如果线程正在执行的是一个Java方法,这个计数器记录的是正在执行的虚拟机字节码指令的地址;如果正在执行的是Native方法,这个计数器值则为空(Undefined)。

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


2、java虚拟机栈

虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧(Stack Frame)用于

存储局部变量表、操作数栈、动态链接、方法出口等信息。

经常有人把Java内存区分为堆内存(Heap)和栈内存(Stack)。“栈”就是现在讲的虚拟机栈,或者说是虚拟机栈中局部变量表部分。


局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型(指向了一条字节码指令的地址)。


在Java虚拟机规范中,对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出Stack-OverflowError异常;

如果虚拟机栈可以动态扩展,如果扩展时无法申请到足够的内存,就会抛出OutOfMemoryError异常。


3、本地方法栈

本地方法栈(Native Method Stack)与虚拟机栈区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。


4、堆

Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。


此内存区域的唯一目的就是存放对象实例。Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。


Java堆是垃圾收集器管理的主要区域


根据Java虚拟机规范的规定,Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可


5、方法区

方法区(Method Area)用于存储已被虚拟机加载的类信息(类名、访问修饰符、字段描述、方法描述)、常量、静态变量、即时编译器编译后的代码等数据。(在目前JDK 1.7的HotSpot中,已经把原本放在永久代的字符串常量池移出。

很多人把方法区称为“永久代”((Permanent Gen-eration)。

相对而言,垃圾收集行为在这个区域是比较少出现的,但并非数据进入了方法区就如永久代的名字一样“永久”存在了。

这区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说,这个区域的回收“成绩”比较难以令人满意,尤其是类型的卸载,条件相当苛刻


6、运行时常量池

运行时常量池(Runtime Constant Pool)是方法区的一部分。Class文件中除了有类的版本、字段、方法、接口等描述信息外,

还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。

运行期间也可能将新的常量放入池中,这种特性被开发人员利用得比较多的便是String类的intern()方法


String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;

否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。

0 0
原创粉丝点击