java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则依赖用户线程的启动和结束而建立和销毁。
程序计数器
程序计数器(Program Counter Register)是线程私有的。是一块较小的内存空间,可以看作是当前线程所执行的字节码的行号指示器。在虚拟机的概念模型里,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
java虚拟机栈
虚拟机栈(Java Virtual Machine Stacks)是线程私有的。java虚拟机栈是描述java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用来存储局部变量表、操作数栈、动态链接、方法出口等信息。每一个方法的调用直至执行完成,都对应着一个栈帧在虚拟机栈中入栈到出栈的过程。通常所说的“堆”中存储“栈”中运行中的“栈”指的就是虚拟机栈,或者说是虚拟机栈中的局部变量表。
局部变量表:存放了编译期可知的各种基本类型(其中64位长度的long和double类型会占用2个局部变量空间(Slot))、对象引用和returnAddress类型。
规定的异常:
- StackOverflowError:当线程请求的栈深度大于虚拟机所允许的深度时抛出。
- OutOfMemoryError:当虚拟机栈进行动态扩展时无法申请到足够的内存空间时抛出。
本地方法栈
本地方法栈(Native Method Stack)与虚拟机栈的作用相似,它们的区别为虚拟机栈为虚拟机执行java方法服务,面本地方法栈则为虚拟机使用到的Native方法服务。
在虚拟机规范中没有对本地方法栈的使用语言、使用方式、数据结构作强制规定,都由具体的虚拟机自由实现。有的虚拟机(譬如Sun HotSpot虚拟机)直接就把本地方法栈和虚拟机栈合二为一。
规定的异常:
- StackOverflowError:当线程请求的栈深度大于虚拟机所允许的深度时抛出。
- OutOfMemoryError:当虚拟机栈进行动态扩展时无法申请到足够的内存空间时抛出。
Java堆
Java堆(Java Heap)是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存的唯一目的就是存入对象实例,几乎所有的对象实例都在这里分配内存。
Java堆是垃圾收集器管理的主要区域。从内存回收角度来看,Java堆还可以细分为:新生代和老年代;再细致一点的有Eden空间、From Survivor空间、To Survivor空间等。
Java堆可以处于物理上不连续的内存空间中,只要逻辑上是连续的即可。可以设置固定大小也可以是可扩展的,可以通过参数 -Xmx和-Xms来控制。
规定的异常:
- OutOfMemoryError:当在堆中没有完成实例分配,并且堆也无法再扩展时抛出。
方法区
方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。从JDK1.7的HotSpot中,已经把原本放在方法区中的字符串常量池移出。从JDK1.8 HotSpot JVM开始使用本地化的内存存放类的元数据,这个空间叫做元空间(Metaspace)这部分可参考文章: JAVA 8 :从永久区(PermGen)到元空间(Metaspace)
运行时常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分。Class 文件中除了有类的版本、字段、方法、接口等描述信息外,还有一项信息是常量池(Constant Pool Table),用于存放编译期生成的各种字面量和符号引用。