JAVA虚拟机学习实践1-简介

来源:互联网 发布:mac的数据库软件 编辑:程序博客网 时间:2024/05/10 16:54

JAVA运行时数据区域总览

根据Java虚拟机的规范规定,Java虚拟机所管理的内存将会包含以下几个运行时数区域,如图1-1所示:


              图1-1

其中,红线环绕的数据区域由所有线程共享,黑线环绕的部分是线程隔离的。

程序计数器

程序计数器是一块非常小的内存空间,它的作用是可以看作是当前线程所执行的字节码的行号指示器,字节码解释器工作时就是通过修改这个计数器的值来选取下一条需要执行的字节码指令,分支、跳转、循环、线程恢复等都依赖这个计数器来完成。

由于Java虚拟机的多线程是通过线程轮流切换并分配处理执行时间的方式来实现的,因此为了线程切换后恢复到正确的执行位置,第条线程都需要独立的程序计数器,我们称这类内存区域为"线程私有"的内存。

此内存区域没有规定任何OutOfMenoryError的情况。

学习过《操作系统》的同学可能还记得程序状态字寄存器(PSW),可以以类似的思路来理解程序计数器。

JAVA虚拟机栈

Java虚拟机栈也是线程私有的,它的生命同期与线程同步。每一个方法被执行时都会同时创建一个栈帧用于存储局部变量、操作栈、动态链接、方法出口等消息。每一个方法从被调用到执行完成,就是该方法创建的桡帧在虚拟机栈中从入栈到出栈的过程。

局部变量表存放了编译期可知的各种数据基本数据类型、对象引用,其中64位长度的long和double占用两个局部变量空间,其余数据类型占用一个局部变量空间。局部变量表所需要的内存空间在编译时完成分配,当进入一个方法时,这个方法需要要帧中分配多在的局部变量空间是完全确定的,在方法运行期间也不会改变局部变量的大小。

对这个区域规定了两种异常状况:如果线程请求的栈深度大于虚拟机所允许的深度,将会抛出StackOverflowError异常;一般虚拟机栈都是可以动态扩展的,当扩展到无法申请内存时会抛出OutOfMenoryError异常。


本地方法栈

本地方法栈与Java虚拟机栈作用是一样的,只不过Java虚拟机栈为Java虚拟机执行Java方法服务,而本地方法栈为ava虚拟机执行native方法服务。


JAVA堆

Java堆是虚拟机中所管理的内存中最大的一块。Java堆是所有线程共享的一块区域,在虚拟机启动时创建。此内存区域唯一的目的就是存放对象实例,几乎所有的对象实例和数组都在这里分配内存。Java堆是垃圾收集器管理的主要区域,因此很多时候也被称为"GC堆"。

在虚拟机启动时可通过-Xmx和-Xms(最大和最小)来控制Java堆的大小,如果堆中已没有内存来分配实例,且堆再也无法扩展,将会抛出OutOfMenoryError异常。


方法区

方法区与Java堆一样,是各个线程共享的内存区域,它用于已被虚拟机加载的类信息、常量、静态变量、即时编译器编译的代码等数据。

当方法区无法满足内存分配时,将会抛出OutOfMenoryError异常。

运行时常量池

运行时常量池是方法区的一部分,class文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项是常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后存放到方法区的运行时常量池中。

运行时常量池具有动态性,Java语言并不一定要求常量一定只能在编译期间产生,运行期间也可能将新的常量放入池中,当常量池无法再申请内存时将会抛出OutOfMenoryError异常。

直接内存

服务器配置虚拟机参数时,不能例各个区域的总和大于物理内在的限制,否则在进行动态扩展时会出现OutOfMenoryError异常。



对象在虚拟机中的分布

最简单最普通的程序行为,也会涉及到Java栈、Java堆、方法区这三个最重要内存区域的关联关系,如下面这句话的代码:Object obj = new Object(),"Object obj"将会作为本地变量存放在Java栈中,作为一个引用类型数据;"new Object()"将会反映到Java堆中,形成一块存储了Object类型所有实例数据的结构化内存,另外在Java堆中还必须包含能查找到此对象类型数据(如对象类型、父类、实现的接口、方法)的地址信息,这些信息包含存储在方法区中。

Java栈中的reference类型在引用Java堆中的对象时,有两种方式,使用句柄和直接指针:如果是使用句柄,在Java堆中会划分出一块内存来作为句柄池,reference存储的对象就是对象的句柄地址,而句柄中包含了对象的实例数据和对象数据的地址,如图1-2所示:


                                                                                            图1-2

如果用直接指针方式,Java堆中的布局就必须考虑如何放置访问类型数据中的相关信息,reference中存储的就是对象地址:

两种方式各有优势,使用句柄时在对象被移动后,只需要修改句柄中的实例数据指针,而不用修改reference数据,使用直接指针方式的优点是访问速度快。











0 0
原创粉丝点击