JVM之运行时数据区域
1.分类
- 线程共享:方法区、堆
- 线程私有:虚拟机栈、程序计数器、本地方法栈
2.数据区概要
3.线程私有数据区
3.1程序计数器
- 一块较小的内存空间,当前线程所执行的字节码的行号指示器
- 由于多线程通过线程切换实现,每一条线程的指令不受影响,必须保证拥有独立的程序计数器
- 当线程执行Java方法时,它记录的是正在执行的虚拟机字节码指令的地址
- 当线程执行Native方法时,该计数器值为空Undefined
- 此内存区域是唯一一个JVM规范中没有规定任何OutOfMemoryError情况的区域
3.2Java虚拟机栈
- 每个方法在执行的同时都会创建一个栈帧(Stack Frame,方法运行时的基本数据结构)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。
- 每一个方法从调入直至执行完成的过程,就对应这一个栈帧在虚拟机中入栈到出栈的过程。
- 当线程请求的栈深度>虚拟机允许的深度,抛出StackOverFlowError。
- 虚拟机栈可动态扩展下,在扩展时无法申请到足够的内存时,抛出OutOfMemoryError异常。
局部变量表存放编译期可知的各种数据类型,所需内存空间在编译期间完成分配,且在方法运行期间不会改变大小:
- 基本数据类型:boolean、byte、char、short、int、float、long、double
- 对象引用:reference类型,不等同于对象本身,可能是一个指向对象起始地址的引用指针,也可能是指向一个代表对象的句柄或其他与此对象向相关的位置。
- returnAddress类型:指向一条字节码指令的地址
- 64位长的long和double类型的数据占用2个局部变量空间(Slot),其余类型只占用1个。
3.3本地方法栈
- 为虚拟机使用的Native方法服务;而虚拟机栈为虚拟机执行Java字节码服务。
- 也会抛出与虚拟机栈同样的异常。
4.线程共享数据区
4.1Java堆
- 在虚拟机启动时创建,是GC管理的主要区域
- 用于存放对象(包括数组)实例
- 从内存回收(分代收集算法)角度看可分为:新生代、老年代
- Java堆可以处于不连续的内存空间,只要逻辑上是连续的即可,可用-Xmx和-Xms控制空间大小
- 如果堆中没有内存完成实例分配,并且对也无法再扩展,将抛出OutOfMemory异常
4.2方法区
- 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据
- 当方法区无法满足内存分配需求时,将抛出OutOfMemory异常。
运行时常量池,方法区的一部分:
- Class文件中包括类的版本、字段、方法、接口等描述信息,还有常量池,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放。
- Class文件中内容的格式都有严格规定;运行时常量池,JVM规范没有做任何细节的要求
- 运行时常量池具备动态性,java语言并不要求常量一定只有编译期才能产生,即并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中,比图String.intern()方法