java内存区域

运行时数据区域  

  java虚拟机在执行java程序的过程中会把它管理的内存分为不同的数据区域,不同的数据区域功能不同,以及它的创建和销毁时间不同,有的区域随着虚拟机的启动而存在,有的区域依赖用户线程的启动和结束而建立和销毁。

 

程序计数器:是一块小的内存,可以认为是当前线程所执行的字节码的行号指示器。(执行到底哪里了),多线程之间轮流切换分配处理器的执行时间,在任何时刻一个处理执行一个线程中的指令,线程切换后为了能及时恢复到正确的位置,每个线程内都需要一个程序计数器,各个线程之间的计数器互不干扰,是线程的私有内存。
如果程序执行的是java方法,计数器记录的是正在执行的字节码的指令地址,如果执行的是本地方法native method,技术器则为空(undefined)
技术器是唯一一块在java虚拟机规范中没有任何规定OutOfMemoryError情况的区域
 

 Java虚拟机栈:Java虚拟机栈描述的是java方法执行的模型,这部分区域也是线程私有的,生命周期和线程相同。每个java方法执行的时候都会创建一个栈帧(stack frame),这个栈帧用于存储局部变量表,操作站、动态链接、方法出口等信息。每个方法的调用到执行完毕都是对应着一个栈帧在java虚拟栈从入栈到出栈的过程。

局部变量表:~存放了在编译期可知的各种基本数据类型,对象引用类型 (不是对象本身)和 returnAddress类型(执行一条字节码指令的地址)。其中64位的长度的long和double类型的数据会占用2个局部变量空间(slot),其余的数据类型都只占用1个,局部变量表所需要的内存空间在编译期间就已经分配完成。当java方法调用执行的时候,这个方法在栈帧中分配多大的内存已经完全确定了,运行期间是不会改变局部变量表的大小。
在java虚拟机规范中,对此区域规定了两种异常:(1)当线程请求的栈深度大于虚拟机所允许的深度,则会抛出StackOverflowError (2)如果虚拟机动态扩展,当扩展到无法申请到足够的内存空间的时候(系统内存有限),会抛出OutOfMemeryError
 
本地方法栈:Native Method Stack 和 java虚拟机栈发挥的作用是一样,只不过java虚拟机栈是执行java方法,而本地方法栈是执行native方法。同样的道理,本地方法也会抛出StackOverflowError和OutOfMemeryError
 
 
Java堆:java heap 是虚拟机中管理的内存中最大的一块,是所有线程共享的一块内存区域。java heap的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。java虚拟机规范描述的是所有的对象实例和数组都要在堆上分配。
java堆是垃圾收集器管理的主要区域,因此也称为"GC堆".
Java堆可以处于物理上不连续的内存空间中,只需要逻辑连续即可。可以实现成固定大小,也可以实现为可扩展(主流虚拟机都设计成可扩展,通过-Xmx 和 -Xms控制),当java heap没有内存完成实例分配,堆也无法再扩展,将会抛出 OutOfMemeryError
 
 
方法区:Method Area 和 java堆一样,是所有线程共享的内存区域。用于存储虚拟机加载的类信息,静态变量,常量,即时编译器编译后的代码数据等。
运行时常量池:运行时常量池是方法区的一部分,class文件除了有类的版本,方法、接口、字段等的描述信息,还有一项信息就是常量池,用于存放编译时生成的各种字面量和符号引用,而这部分信息在类加载后存放在方法区中的运行时常量池中。运行时常量池受到方法区内存的限制,运行时常量池无法申请到内存时也会抛出OutOfMemeryError异常。
运行时常量池相对于class文件常量池的一个特点是具有动态性,也就是说并非只在编译期间,class文件的常量池的内容才能进入运行时常量池,在运行期间,也有可能将常量放入运行时常量池中,例如:String类的intern()方法
 
 
直接内存:直接内存不是运行时数据区的一部分,不是java虚拟机规范定义的内存区域。在NIO类中,使用native方法直接在堆外分配内存,然后通过在java堆中DirectByteBuffer对象对象作为这块内存的引用进行操作。避免了java堆和native堆之间的数据来回复制,提高了性能。本机的直接内存不会受到java堆大小的限制,但是还是会受本机内存大小的限制。当配置各个内存区域大小的时候,忽略了直接内存,使得各个区域内存大小之和大于物理内存限制,则会抛出OutOfMemeryError异常。
原文地址:https://www.cnblogs.com/xiaojianfeng/p/9353317.html