Java运行时数据区总结
目录
运行时数据区划分图
详细描述
程序计数器
- 线程私有,存取下一条需要执行的字节码指令,它是程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都需要依赖这个计数器来完成
Java虚拟机栈
- 线程私有,每个方法被执行的时候,Java虚拟机都会同步创建一个栈帧[插图](Stack Frame)用于存储局部变量表、操作数栈、动态连接、方法出口等信息
- 常说的堆栈中的栈就是这里的虚拟机栈
- 局部变量表所需的内存空间在编译期间完成分配,当进入一个方法时,这个方法需要在栈帧中分配多大的局部变量空间是完全确定的,是指的变量槽确定(其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个)
- StackOverflowError和OutOfMemoryError
本地方法栈
- 为虚拟机使用到的本地(Native)方法服务,《Java虚拟机规范》对本地方法栈中方法使用的语言、使用方式与数据结构并没有任何强制规定
- StackOverflowError和OutOfMemoryError
Java堆
- 所有线程共享的,虚拟机启动时创建,“几乎”所有的对象实例都在这里分配内存(由于即时编译技术的进步,尤其是逃逸分析技术的日渐强大,栈上分配、标量替换[插图]优化手段已经导致一些微妙的变化悄然发生)
- GC堆
- “新生代”“老年代”“永久代”“Eden空间”“From Survivor空间”“To Survivor空间”,这些区域划分仅仅是一部分垃圾收集器的共同特性或者说设计风格而已
- 通过参数-Xmx和-Xms设定
方法区
- 各个线程共享,“非堆”(Non-Heap)
- 永久代称呼来源---当时的HotSpot虚拟机设计团队选择把收集器的分代设计扩展至方法区,或者说使用永久代来实现方法区而已,这样使得HotSpot的垃圾收集器能够像管理Java堆一样管理这部分内存,省去专门为方法区编写内存管理代码的工作
- 【对常量池的回收和对类型的卸载】这区域的内存回收目标主要是针对常量池的回收和对类型的卸载,一般来说这个区域的回收效果比较难令人满意,尤其是类型的卸载,条件相当苛刻,但是这部分区域的回收有时又确实是必要的
- 【JDK8开始,废弃永久代,在本地内存中实现元空间(Meta-space)来代替,主要是存放类型信息】
- 【运行时常量池】
1、预置入Class文件中常量池(Constant Pool Table)的内容
2、运行期间也可以将新的常量放入池中(String类的intern()方法)
-XX:MaxPermSize
直接内存
并不是虚拟机运行时数据区的一部分,在JDK 1.4中新加入了NIO(New Input/Output)类,引入了一种基于通道(Channel)与缓冲区(Buffer)的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据
参考:来源于《深入理解Java虚拟机第三版》