一分钟扫盲:Java虚拟机运行时数据区
Java虚拟机所管理的内存将会包括以下5个运行时数据区域:
-
方法区
-
堆
-
虚拟机栈
-
本地方法栈
-
程序计数器
线程私有:每个线程都会有自己独立的空间,随线程的生命周期而创建和销毁。
线程共享:所有线程都能访问到的内存空间,随虚拟机或GC而创建和销毁。
1. 程序计数器(Program Counter Register):
-
是什么:
一块较小的内存空间,可看做当前线程所执行的字节码的行号指示器。
-
是否线程私有: 是
-
存什么:
-
如果线程正在执行的是Java方法,那么计数器记录的正在执行的虚拟机字节码指令的地址;
-
如果线程正在执行的是Native方法,那么计数器值则为空(Undefined)。
-
-
异常:唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError。
为什么说不会出现OutOfMemoryError?首先我们得知道什么原因才会出现OutOfMemoryError,只有需要申请增加内存,但系统以及没有多余的内存的时候,才会出现内存溢出错误。程序计数器它只是存了个线程执行的字节码指令地址而已,并不会重新申请更多的内存,就不会出现内存溢出。
2. Java虚拟机栈(栈)(Java Virtual Machine Stacks):
-
是什么:
虚拟机栈描述的是Java方法执行的内存模型,每个方法从调用直至执行完成的过程,就对应这一个栈帧在虚拟机栈中入栈到出栈的过程。
栈帧:每个方法在执行的同时都会创建一个栈帧,用存储 局部变量表、操作数占、动态链接、方法出口等信息。
局部变量表:存放了编译器可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用和returnAddress类型(指向了一条字节码指令的地址)
-
是否线程私有:是
-
存什么:栈帧
-
异常: StackOverflowError、OutOfMemoryError
-
StackOverflowError:如果线程请求的栈深度大于虚拟机所允许的深度,将抛出异常。
-
OutOfMemoryError:如果虚拟机栈可以动态扩展(当前大部分Java虚拟机都可动态扩展,只不过Java虚拟机规范也允许固定长度的虚拟机栈),如果扩展时无法申请到足够的内存,就会抛出异常。
-
3. 本地方法栈(Native Method Stack):
-
是什么:
本地方法栈为虚拟机使用到的Native方法服务。
跟Java虚拟机栈非常相似,只不过Java虚拟机栈是为虚拟机执行Java方法(也就是字节码)服务
-
是否线程私有: 是
-
存什么: 栈帧
-
异常: StackOverflowError、OutOfMemoryError
4. Java堆(Java Heap):
-
是什么:
-
唯一的目的是存放对象实例,几乎所有的对象实例都在这里分配内存。
-
Java虚拟机所管理的内存中最大的一块。
-
被所有线程共享,在虚拟机启动是创建。
-
-
是否线程私有: 否
-
存什么: 对象实例
-
异常: OutOfMemoryError
5. 方法区(Method Area):
-
是什么:
虽然Java虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却有一个别名叫做Non-Heap(非堆),目的应该是与Java堆区分开来。
-
是否线程私有: 否
-
存什么: 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
-
异常: OutOfMemoryError
6. 运行时常量池(Runtime Constant Pool):
-
是什么:
运行时常量池是方法区的一部分。
-
是否线程私有: 否
-
存什么: 编译期生成的各种字面量和符号引用,这部分将在类加载后进入方法区的运行时常量池中存放。
-
异常: OutOfMemoryError
参考:《深入理解Java虚拟机》