运行时数据区的结构
大至结构如下图所示,其中白色部分为线程私有,灰色部分为线程共享部分

程序计数器
程序计数器可以看成当前线程字节码的行号指示器(下一行要执行什么程序),计数器记录的是正在执行的虚拟机字节码指令地址
当我们执行多线程程序时,多线程程序是线程轮流切换,一个处理器都会执行一条线程的指令,因此为了线程切换后能恢复到正确的执行位置,每条线程都需要有有一个独立的程序计数器(线程私有)

虚拟机栈
虚拟机栈是线程私有的,为防止并发访问时造成冲突。
虚拟机栈包含的四部分
-
局部变量表(Local Variable Table):存储方法参数、局部变量(基本类型值、对象引用)。
-
操作数栈(Operand Stack):用于字节码指令的运算(如加减乘除、创建对象的引用等操作)。
-
动态链接(Dynamic Linking):存储方法的符号引用,指向方法在方法区的元数据(如类、接口信息),用于动态绑定(多态时解析实际调用的方法)。
-
方法父类实现,子类也有实现 当子类重写父类方法时,通过动态链接在运行时确定实际调用的子类方法
-
符号引用(如类名、方法名)存储在方法区的常量池中,动态链接通过常量池解析到具体方法的内存地址。
-
-
方法返回地址(Return Address) :记录方法执行完成后返回的位置(如调用者的下一条指令地址),与
return
、try-catch
逻辑相关。
本地方法栈
与虚拟机栈所发挥的作用是非常相似的,其区别只是虚拟机 栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的本地(Native)方法服务
堆
内存中最大的一块,是所有线程共享的内存区域
是存放对象的位置,"几乎"所有的对象实例以及数组都在堆上进行分配
是垃圾收集器所管理的内存区域(于现代垃圾收集器大部分都是基于分 代收集理论设计的------"新生代""老年代""永久代")
从分配内存的角度看,所有线程共享的Java堆中可以划分出多个线程私有的分配缓冲区 ------TLAB(先从堆中分出一块内存给一个线程,分出另一块分给另一个线程,用完再进行申请,减少交互,类似银行取钱,不可能用多少取多少,而是先给100先用,用完再申请)
方法区
(1)方法区是各个线程共享的内存区域
(2)方法区在JVM启动的时候被创建,随 JVM 关闭而销毁 ,并且它的实际物理内存空间和Java堆区一样都可以是不连续的。
(3)方法区会发生内存溢出(OOM)
(4)元空间不在虚拟机设置的内存中,而是使用本地内存
方法区的内部结构
方法区用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存、域信息等
类型信息:对每个加载的类型(class、interface,enum、annotation),jvm要存储类型信息有该类型和直接父类的完整有效名称(interface和Object没有父类)、该类型的修饰符和该类型直接接口的一个有序列表
域信息:JVM须在方法区保存类型的所有域的相关信息以及域的声明顺序
方法信息:方法名称、返回值类型,修饰符等
运行时常量池
保存Class文件中描述的符号引用外,还会把由符号引用(com.qcby.school)翻译出来 的直接引用也存储在运行时常量池中