四、运行时数据区
基础划分总结
- 线程共享:堆、元数据区(方法区)
- 线程私有:程序计数器、虚拟机栈、本地方法栈
- 会发生 OOM(Out Of Memory,直译:内存溢出 / 内存耗尽):堆、元数据区、虚拟机栈、本地方法栈
- 会进行 GC:堆、元数据区


1. 各区域核心说明
| 程序计数器 | 记录线程当前执行指令位置,CPU 切换线程后恢复执行 | ** |
| 虚拟机栈 | 执行 Java 方法,每个方法对应一个栈帧 | 线程私有;先进后出;无 GC、会 OOM;引用类型存对象地址,对象存在堆中 |
| 本地方法栈 | 执行 native 修饰、C/C++ 实现的本地方法 | 线程私有;无 GC、会 OOM |
| 堆 | 存放所有 new 出来的对象实例 | JVM 最大内存区;可通过 -Xms 初始堆、-Xmx 最大堆 配置;GC 最主要区域 |
| 元数据区(方法区) | 存储类结构信息、静态常量、编译后代码 | 线程共享;JDK1.8 用元空间替代永久代;有 GC(回收废弃类信息,条件苛刻) |
2、程序计数器
作用
用来记录线程执行的指令集的位置,因为线程在执行时cpu要切换执行,需要记录线程执行的位置
特点
1、是运行时数据区中空间最小的,运行速度最快的区域
2、每个线程都有一个自己的程序计数器,是线程私有的,程序计数器生命周期与线程生命周期相同
3、程序计数器是运行时数据区中唯一一个不会有内存异常情况的区域
3、虚拟机栈
概述
虚拟机栈是运行单位,管理程序如何执行,调用一个方法运行结束后出栈。
虚拟机栈主要用来运行java语言写的方法
特点
1、是线程私有的,每个线程中调用的方法都在线程中对应的虚拟机栈中执行
2、栈中存储局部变量
3、虚拟机栈终会存在内存溢出问题
4、引用类型在栈中存储的是对象的地址,对象存在堆中
5、A线程中的方法(栈帧)不能调用B线程中的方法(栈帧)
6、先进先出
7、栈中不存在垃圾回收
栈帧
当一个方法被调用后,被压入虚拟机栈中称为一个栈桢
内部结构:
局部变量表(存储局部变量的区域),
操作数栈:操作数栈就是用来计算的区域
例如:
int a=10; int b=20; //a和b存储到局部变量表
int c=a+b;//从局部变量表中加载a和b到操作数栈,在操作数栈中进行运算,将运算结果赋给c,把c写到局部变量表中
4、本地方法栈&本地方法
概述
本地方法(C/C++编写):(这里指在java程序中)不是java语言实现的方法
使用native关键字修饰的方法,没有方法体
java语言属于上层语言(开发上层应用程序)没有权限与底层硬件进行交互(如读取内存数据,读取硬盘数据)
本地方法栈用来执行本地方法,当程序中调用本地方法那么就会被加载到本地方法栈中运行
本地方法栈管理本地方法的调用
特点
1、本地方法栈是线程私有的,每个线程都有属于自己的本地方法栈
2、本地方法栈也会出现内存溢出
3、本地方法栈不会出现垃圾回收
5、堆
作用
堆空间是用来存储Java中创建的对象
特点
堆空间是运行时数据区中最大的一块内存区域
可以根据需求通过参数设置大小(-Xms:10m(堆起始大小) -Xmx:30m(堆最大内存大小))
堆空间会出现内存溢出的情况
堆空间是垃圾回收的重点区域
堆内存区域划分
新生区(代):
Eden(伊甸园区)
Survivor(幸存者区):From(幸存者0) ,To(幸存者1)
老年区(代)

为什么分区(分区目的)
根据对象存活周期和大小不同放在不同区域,不同区域使用不同 GC 算法;新生代频繁回收、老年代较少回收,提升垃圾回收整体效率。
对象创建堆内存分配


堆空间参数
JVM调优(面试题)
具体参考oracle的APi文档了解具体参数,进项JVM的配置
6、元数据区(方法区)
概述
主要存放类信息(属性,方法,静态常量。。。。)和编译器编译后的代码
特点
是被线程共享的
物理上讲堆和方法区是整体,逻辑上讲堆和方法去是分开的
方法区的大小也是可以调整的,方法区的大小决定可以加载多少类
方法区也可能出现内存溢出
方法区,栈,堆的交互关系

方法区垃圾回收
方法区是有垃圾回收的,方法区的垃圾回收主要是回收类信息。
类信息的回收条件比较苛刻:
1、该类所常见的对象不再使用,并且回收了
2、该类的Class对象也不再使用了
3、加载该类的类加载器也被回收了
7、为什么要使用元空间来替换永久代?
1、在1.7版本里面,永久代内存是有上限的,虽然我们可以通过参数来设置,但是JVM加载的class总数、大小是很难确定的。所以很容易出现OOM(Out Of Memory,直译:内存溢出 / 内存耗尽)问题。但是元空间是存储在本地内存里面,内存上限比较大,可以很好的避免这个问题。
2、永久代的对象是通过FullGC进行垃圾收集,也就是和老年代同时实现垃圾收集。替换成元空间以后,简化了Full GC。可以在不进行暂停的情况下并发地释放类数据,同时也提升了GC的性能
