Java内存区域
1.1 程序计数器(线程私有)
概念 : 一块较小的内存区域,可看作为当前行号的指示器
作用 :(1) 通过改变计数器的值选取吓一跳需要执行的字节码指令
(2) 作为控制流的的指示器,分支,循环,跳转,异常处理,线程恢复等等需要依靠计数器完成
异常:是《java虚拟机规范》中没有任何规定OOM的区域
2.1 虚拟机栈(线程私有)、
概念 : 生命周期与线程相同,虚拟机栈描述的是java方法的内存模型
每个方法创建的时候都会同步创建一个栈帧
栈帧用于存储局部变量表,操作数栈,动态链接,方法出口 等信息
每一个方法被掉哦那个直至执行完毕的过程,对应一个栈帧,入栈到出栈的过程
异常 : (1)线程请求的栈深度 > 虚拟机栈允许深度 --->>>StackOverflowError
(2)如果虚拟机栈容量可以动态扩展,当栈扩展时无法申请到足够的空间---->>>OOM
*注意:HotSpot是不支持动态扩展的,所以HotSpot上不会因为虚拟机栈无法扩展而导致OOM(只要线程申请栈空间成功就不会有OOM)
但是如果申请时就失败了,会出现OOM *
3.1 本地方法栈(线程私有)
概念 :与虚拟机栈发挥的作用相似,本地方法栈是为虚拟机使用到的本地方法服务
4.1 堆(线程共享)
概念 :所有的对象实例以及数组都应该在堆上分配
异常 :java堆中没有内存完成分配,且堆 也无法再扩展,java虚拟机抛出OOM
5.1 方法区(共享)
概念:存储已经被虚拟机加载的类信息,常量就,静态变量,即时编译器编译后的代码缓存等数据
异常: 如果方法区无法满足新的内存分配需求,将抛出OOM
扩展:
永久代:
永久代并不等价于方法区
如何实现永久代不受《java虚拟机规范》的约束,并不要求统一
jdk6及其以前----使用永久代实现方法区
jdk7---将原本在永久代的字符串常量池,静态变量移除
jdk8---放弃永久代,在本地内存中实现的原空间代替
5.1.1运行时常量池
概念 :用于存放编译器生成的各种字面量和符号引用
特点 : 动态性
常量并不一定只有编译器才能生成,运行期间也可以将新的常量放入常量池
例如String的intern()
异常 : 因为时方法区的一部分,收到方法区的内存限制,常量池无法申请到足够内存时---OOM
6.1 直接内存(不是虚拟机运行时的一部分)
概念:java直接操作的本地内存
用途:jdk1.4引入NIO ,可以使用Native函数库直接分配对外内存
这样能在一些场景显著提高性能,因为避免了java堆和Native堆来回复制内存
异常:收到本机内存和寻址空间的限制 ,一般会根据实际内存去设置-Xmx等信息,但经常忽略直接内存
使得各个内存区域总和大于物理内存限制,从而导致动态扩展时 OOM