总览
JVM 运行时数据区主要有以下几类
- JVM栈 (Java Virtual Machine Stacks)
- 堆内存 (Heap Memory)
- 方法区 (Method Area)
- 本地方法栈 (Native Method Stacks)
- 程序计数器 (Program Counter (PC) Register)
引用https://blog.csdn.net/zhangqiluGrubby/article/details/59110906中的一张图:
在这几类中, JVM栈/本地方法栈是每个线程均分配一个, 堆内存/方法区是所有线程共享.
各类数据区详细分析
1. JVM栈 (Java Virtual Machine Stacks)
在介绍 JVM栈 之前, 先了解一下 栈帧 概念
栈帧:存放方法中的基础数据类型对象和自定义对象的引用(不是对象, 对象都存放在堆区中), 操作数栈等数据, 一个栈帧随着一个方法的调用开始而创建, 这个方法调用完成而销毁.
而 JVM栈 就是一个栈帧的集合, JVM栈只对栈帧进行存储, 压栈和出栈操作.
每个线程包含一个栈区.
栈内存的大小可以有两种设置, 固定值和根据线程需要动态增长.
在JVM栈这个数据区可能会发生抛出两种错误.
- StackOverflowError 出现在栈内存设置成固定值的时候, 当程序执行需要的栈内存超过设定的固定值会抛出这个错误.
- OutOfMemoryError 出现在栈内存设置成动态增长的时候, 当JVM尝试申请的内存大小超过了其可用内存时会抛出这个错误.
2. 堆内存 (Heap Memory)
堆数据区是用来存放对象和数组(特殊的对象). 堆内存由多个线程共享. 堆内存随着JVM启动而创建. 回收对象释放内存的垃圾回收操作就是发生在这个数据区. 如果堆内存剩余的内存不足以满足于对象创建时, JVM会抛出OutOfMemoryError错误.
总结
- 存储的全部是对象, 每个对象包含一个与之对应的class信息(class信息用于获取操作指令).
- jvm只有一个堆区(heap)被所有线程共享, 堆区中不存放基本类型和对象引用, 只存放对象本身.
- 堆的优势是可以动态地分配内存大小, 生存期也不必事先告诉编译器, 因为它是在运行时动态分配内存的, Java的垃圾收集器会自动收走这些不再使用的数据.
- 缺点是, 由于要在运行时动态分配内存, 存取速度较慢.
我们平时说的GC/老年代/新生代均是在此区域的概念, 具体请看: JVM 垃圾回收的一些知识( 新生代老年代 / MinorGC和MajorGC / 可达分析与回收算法 )
3. 方法区 (Method Area)
方法区与堆一样, 是被线程共享的区域. 在方法区中, 存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等.
方法区中存有一个非常重要的部分: 运行时常量池, 它是每一个类或接口的常量池的运行时表示形式, 在类和接口被加载到JVM后, 对应的运行时常量池就被创建出来.
4. 本地方法栈 (Native Method Stacks)
本地方法栈是JVM实现了native方法调用支持的数据区, 一般为C或者C++所写.
本地方法栈基本和JVM栈一样, 其大小也是可以设置为固定值或者动态增加, 因此也会对应抛出StackOverflowError和OutOfMemoryError错误.
5. 程序计数器 (Program Counter (PC) Register)
- 可简单认为是指令行号, 如果是本地方法指令, 则指向undefined;
- 单线程私有;
- 不抛出OutOfMemoryError的运行时数据区.
参考引用: