PC寄存器
- 每个线程都有一个程序计数器,是线程私有的,就是一个指针,指向方法区中的方法字节码
方法区
-
方法区被所有线程共享
-
静态变量,静态方法,常量,类信息(构造方法,接口定义),运行时的常量池
-
static,final,Class类模板信息
方法栈
public class MethodTest {
public static void main(String[] args) {
MethodTest methodTest = new MethodTest();
methodTest.stackMethod_1();
methodTest.stackMethod_2();
}
void stackMethod_1() {
System.out.println("入栈");
}
void stackMethod_2() {
System.out.println("入栈");
}
}
- image-20200517160755368.png
-
栈内存,主管程序的运行,生命周期和线程同步
-
线程结束,栈内存也就释放,
栈不存在垃圾回收
-
程序正在执行的方法一定在
栈顶
-
8大基本类型 + 对象引用 + 实例方法
栈溢出
- 方法无限相互调用,超过栈的存储空间
对象创建简化版内存模型
- image-20200517165651898.png
对象创建过程
- image-20200517170459644.png
堆
- 一个JVM只有一个堆内存,堆内存的大小是可以调节的
- 堆内存分为三个区域
- 新市区
- 老年区
- 永久区
堆内存空间
- image-20200517194543774.png
-
From区和To区会相互交换
永久区的变化
- 这个区域的是常驻内存,用来存放JDK自身携带的Class对象,interface元数据,存储的一些环境和类信息,这个区域不存在垃圾回收,关闭
JVM就会释放
- jdk1.6之前:永久代,常量池是在方法区
- jdk1.7:永久代,常量池放入堆中
- jdk1.8后:无永久代,常量池在元空间
各区域详解
程序计数器
-
字节码解释器
改变程序计数器来依次读取指令
,实现顺序执行,循环,选择,异常处理 -
记录当前线程
执行的位置
,便于线程切换回来的时候知道上次运行的位置
Java虚拟机栈
- 主要存放8大基本类型,对象引用
- 方法的出口信息
本地方法栈
- 则为虚拟机使用到的Native方法
堆
- 存放对象实例
- 新生代(Eden空间,From Survivor,ToSurvivor)和老年代
- JDK1.8移除整个永久代,取而代之的是元空间的区域(永久代使用的是堆内存空间,元空间使用的是物理内存)
方法区
- 加载的类信息,常量,静态变量
运行时常量池
-
用来存放编译期生成的各种字面量和符号引用
-
字面量(文本字符串,被声明为final的常量值,基本数据类型的值)
-
JDK1.7之后,
常量池
从方法区
中移到了堆中
JDK1.8内存模型
- image.png
-
JDK1.8后永久代移除,变为元空间
-
方法区概念保留,转移到了元空间
-
常量池移到了堆种
-
方法区移到本地内存的原因:IO操作更快
参考
- 参考自狂神的B站视频
- JavaGuide的内存分析
网友评论