java 内存划分

2016-03-14 20:28:12   最后更新: 2016-03-15 16:22:08   访问数量:566




java 虚拟机在 java 程序执行过程中会将内存划分为若干个不同的数据区域,如下图所示:

 

 

程序计数器是一块较小的内存空间,他存储了正在执行的虚拟机字节码指令的地址

通过改变程序计数器来选取下一条需要执行的字节码指令

这块内存被每个线程私有,且是唯一不会抛出 OutOfMemoryError 的内存区域

 

java 虚拟机栈描述的是 java 方法执行的内存模型,每个方法在执行的同时都会创建一个栈帧,用于存储方法局部变量表、操作数、动态链接、方法出口等信息

这部分内存是线程私有的,其生命周期与线程生命周期相同,通过虚拟机运行参数中的 -Xss 参数可以设定他的大小

每调用一个方法,则这个方法在线程私有的 java 虚拟机栈中创建一个栈帧,方法调用结束则出栈

虚拟机栈空间中的局部变量表以 Slot 为单位进行内存的分配,每个 Slot 32bit,他在编译期间完成内存的分配

 

如果线程请求的栈深度大于虚拟机所允许的深度,就会抛出 StackOverflowError 异常

如果虚拟机可以动态扩展,在动态扩展时无法申请到足够内存,则会抛出 OutOfMemoryError 异常

 

本地方法栈与虚拟机栈非常像,他只为 native 方法提供存储空间,有的实现中本地方法栈与虚拟机栈使用的是相同的内存空间

通过 -Xoss 参数可以设置本地方法栈的大小

在 HotSpot 虚拟机中,并不区分虚拟机栈和本地方法栈,所以 -Xoss 是无效的

如果栈帧过大或是栈容量太小,就会抛出 StackOverflowError 异常

 

对于大多数应用来说,java 堆是 jvm 管理的内存中最大的一块

java 的堆是所有线程共享的内存区域,在虚拟机启动时创建,他的唯一用途就是创建对象的实例,几乎所有对象实例都在这里分配

这里也是垃圾收集器管理的主要区域,因此,java 堆也常常称为 GC 堆

java 堆中还可细分为新生代和老年代,甚至进一步细分为很多空间,从分配角度划分,java 堆可以划分出多个线程私有的分配缓冲区(TLAB)

按照 java 虚拟机规范,java 堆处于物理上不连续的内存空间中,在逻辑上他是连续的整块内存

当前主流 jvm 实现中,java 堆是可扩展大小的,通过 -Xmx 和 —Xms 控制,可以参看 jvm 参数配置相关的日志

如果堆无法扩展则会抛出 OutOfMemoryError 异常

 

方法区与 java 堆一样,是各个线程共享的内存区域,他用于存储已经被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

java 虚拟机规范中把方法区描述为堆的一个逻辑部分,但是他却有一个别名 -- Non-Heap,“非堆”

方法区与 java 堆一样,不要求使用连续内存,但在逻辑上是连续的,并且可以无需使用垃圾收集,有的实现中,会对常量池进行内存的回收,对类型进行卸载

可以通过 -XX:PermSize 和 -XX:MaxPermSize 限制方法去的大小

如果方法区无法满足内存分配需求,就会抛出 OutOfMemoryError 异常

 

《深入理解 Java 虚拟机 -- jvm 高级特性与最佳实践(第 2 版)》

 






读书笔记      技术帖      龙潭书斋      内存      memory      java      分区      jvm      java虚拟机     


京ICP备15018585号