概述
java的内存控制权力归属于java虚拟机,在虚拟机自动内存管理机制的帮助下,不再需要为每次一个new操作去写delete/free代码,不容易出现内存泄漏问题。因此一旦出现内存泄漏和溢出方面问题,为了排查错误,需要了解虚拟机如何使用内存。
运行时数据区域
- 程序计数器(Program Counter Register):较小的内存空间,可以看做当前线程执行的字节码的行号指示器,即通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支,循环,跳转,异常处理,线程恢复等功能。
- 线程私有:每个线程都有一个独立的计数器,各条线程之间计数器互不影响,独立存储
- 线程执行java方法,计数器记录正在执行的虚拟机字节码指令的地址
- 线程执行native方法,计数器值为空
- 此内存区域在java虚拟机中没有任何OutOfMemoryError情况的区域
- Java虚拟机栈(Java Virtual Machine Stacks)
- 线程私有,生命周期与线程相同
- 描述Java方法执行的内存模型,每个方法执行时会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等。每个方法调用直至执行完成的过程中,就对应着一个栈帧在虚拟机栈中如占到出栈的过程
- 局部变量表:存放基本数据类型,对象引用,returnAddres类型。局部变量表内存空间在编译过程中完成分配,进入一个方法时,这个方法需要在帧中分配多大局部空间是完全确定的,方法运行期间不会改变
- 异常
StackOverflow异常: 线程请求的栈深度大于虚拟机栈允许的深度
OutOfMemoryError异常: 虚拟机动态扩展但是却无法申请到足够的内存
-
本地方法栈(Native Method Stack)
虚拟机栈为虚拟机执行Java方法,而本地方法栈为虚拟机使用到的Native方法服务。本地方法也会跑出 StackOverflowError 和 OutOfMemoryError 异常 -
Java堆(Java Heap)
- Java管理内存中最大的一块。所有线程共享并且存放对象实例
- Java堆也是垃圾收集器管理的主要区域
- Java堆可以处于物理不连续的空间中,只要逻辑连续即可。
- 如果堆中内存没有完成实例分配,并且堆也无法扩展时,将会抛出OutOfMemoryError
- 方法区(Method Area,别名非堆Non-Heap)
- 同Java堆一样,是各个线程共享的内存区域,用处存储已被虚拟机加载的类信息,常量,变量,编译后的代码
- 运行时常量池(Runtime Constant Pool)
- 方法区的一部分, Class文件中除了类,方法,接口外,还有一项信息就是常量池,用于存放编译器生成的各种字面量和符号引用。
- 运行时常量池相对于Class文件常量池的另外一个重要特征时动态性
- 当常量池无法申请内存时,抛出OutOfMemoryError
- 直接内存(Direct Memory)
不是虚拟机运行时数据区,也不是Java虚拟机规范中定义的内存区域