首页 > 代码库 > java内存结构(执行时数据区域)

java内存结构(执行时数据区域)

java虚拟机规范规定的java虚拟机内存事实上就是java虚拟机执行时数据区,其架构例如以下:
技术分享

当中方法区和堆是由全部线程共享的数据区。

Java虚拟机栈。本地方法栈和程序计数器是线程隔离的数据区。

(1).程序计数器:

是一块较小的内存空间,其作用能够看作是当前线程所运行的字节码的行号指示器,字节码解析器工作时通过改变程序计数器的值来选取下一条须要运行的字节码指令。

程序的分支、循环、跳转、异常处理以及线程恢复等基础功能都是依赖程序计数器来完毕。

Java虚拟机的多线程是通过线程轮流切换并分配处理器运行时间片来实现。在不论什么一个时刻,一个处理器仅仅会运行一条线程指令。因此。为了确保线程切换之后能恢复到正确的运行位置,每条线程都须要一个独立的程序计数器,因此程序计数器是线程私有的内存。

程序计数器是java虚拟机中唯一一个没有规定不论什么内存溢出OutOfMemoryError的内存区域。

(2).java虚拟机栈:

Java虚拟机栈也是线程私有的。它的生命周期与线程同样。

虚拟机栈描写叙述的是java方法运行的内存模型:每一个方法被运行时都会同一时候创建一个栈帧用于存放局部变量表、操作数栈、动态连接和方法出口等信息。每一个方法被调用直至运行完毕过程,就相应着一个栈帧在虚拟机中从入栈到出栈的过程。

Java虚拟机栈的局部变量表存放了编译器可知的8种java基本类型数据、对象引用(注意不是对象实例本身)、方法返回地址returnAddress。

Java虚拟机栈的局部变量表空间单位是槽(Slot),当中64位长度的double和long类型会占用两个slot。其余的数据类型仅仅占用一个slot。

局部变量表所需内存空间在编译期间完毕分配,当进入一个方法时。该方法须要在帧中分配多大的局部变量空间是全然确定的,在方法执行期间不会改变局部变量表的大小。

Java虚拟机栈有两种异常状况:假设线程请求的栈深度大于虚拟机所同意的最大深度时,抛出StackOverflowError异常;假设虚拟机栈能够动态扩展,当扩展时无法申请到足够内存时会抛出OutOfMemoryError异常。

(3).本地方法栈:

本地方法栈与java虚拟机栈作用很类似。其差别是:java虚拟机栈是为虚拟机运行java方法服务。而本地方法栈是为虚拟机调用的操作系统本地方法服务。

Java虚拟机规范没有对本地方法栈的实现和数据结构做强制规定。Sun HotSpot虚拟机直接把java虚拟机栈和本地方法栈合二为一。

与java虚拟机栈类似,本地方法栈也会抛出StackOverflowError异常和OutOfMemoryError异常。

(4).堆:

堆是java虚拟机所管理的内存区域中最大一块,java堆是被全部线程所共享的一块内存区域。在java虚拟机启动时创建。堆内存的唯一目的就是存放对象实例。差点儿全部的对象实例都是在堆分配内存。

Java堆是垃圾收集器管理的主要区域。从垃圾回收的角度看,因为如今的垃圾收集器基本都採用的是分代收集算法。因此java堆还能够初步细分为新生代和年老代。

Java虚拟机规范规定,堆能够处于物理上不连续的内存空间中,仅仅要逻辑上是连续的就可以。在实现上即能够是固定大小的。也能够是可动态扩展的。假设在堆中没有内存完毕实例分配,而且堆大小也无法在扩展时,将会抛出OutOfMemoryError异常。

(5).方法区:

方法区与堆一样,是被各个线程共享的内存区域。它用于存储已被虚拟机载入的类信息、常量、静态变量、即时编译后的代码等数据。尽管java虚拟机规范把方法区描写叙述为堆的一个逻辑部分,可是方法区却有一个别名叫Non-Heap(非堆)。

Sun HotSpot虚拟机把方法区叫永久代(Permanent Generation),方法区中最重要的部分是执行时常量池。

Class文件里除了有类的版本号、字段、方法、接口等描写叙述信息外,另一项信息是常量池。用于存放编译期生成的各种字面变量、符号引用、直接引用等,这些内容将在类载入后存放到方法区的执行时常量池中,另外在执行期间也能够将新的常量存放到常量池中,如String的intern()方法。

方法区和执行时常量池在无法满足内存分配时,也会抛出OutOfMemoryError异常。

(6).直接内存:

直接内存并非java虚拟机执行时数据区的一部分,也不是java虚拟机规范中定义的内存区域。可是在java开发中还是会使用到。

JDK1.4中新引入的NIO(new I/O),引入了一种基于通道(Channel)和缓冲区(Buffer)的I/O方式,能够使用操作系统本地方法库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为堆外直接内存的引用进行操作,避免了java堆内存和本地直接内存间的数据拷贝,能够显著提高性能。

尽管直接内存并不直接收到java虚拟机内存影响。可是假设java虚拟机各个内存区域总和大于物理内存限制,从而导致直接内存不足,动态扩展时也会抛出OutOfMemoryError异常。

java虚拟机内存结构中的程序计数器、虚拟机栈和本地方法栈这三个区域随线程创建而生,随线程销毁而灭,因此这三个区域的内存分配和回收是确定的。java垃圾收集器重点关注的是java虚拟机的堆内存和方法区内存。

java内存结构(执行时数据区域)