侧边栏壁纸
博主头像
Dioxide-CN博主等级

茶边话旧,看几许星迢露冕,从淮海南来。

  • 累计撰写 54 篇文章
  • 累计创建 30 个标签
  • 累计收到 24 条评论

目 录CONTENT

文章目录

运行时数据区

Dioxide-CN
2023-01-12 / 0 评论 / 3 点赞 / 41 阅读 / 1,583 字
温馨提示:
本文最后更新于 2023-01-12,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

运行时数据区

官方解读

Chapter 2. The Structure of the Java Virtual Machine (oracle.com)
The Java Virtual Machine defines various run-time data areas that are used during execution of a program. Some of these data areas are created on Java Virtual Machine start-up and are destroyed only when the Java Virtual Machine exits. Other data areas are per thread. Per-thread data areas are created when a thread is created and destroyed when the thread exits.

5007d3825e2c830e40879b9660234bdc

方法区

基本概念

JVM 只有一个方法区,且是被所有 JVM 线程共享的,方法区的生命周期是与 JVM 互相绑定的。方法区拥有以下特点:

  1. 方法区是各个线程共享的内存区域,在虚拟机启动时创建
  2. 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器变异后的代码等数据
  3. 对染 Java 虚拟机规范把方法区描述为堆的一个逻辑部分,但是它却又有一个别名叫做 Non-Heap(非堆),目的是与 Java 堆区分开来
  4. 当方法区无法满足内存分配需求时,讲会抛出 OOM 异常
  5. 方法区在 JDK8 中就是 Metaspace 元空间,在 JDK6 和 7 中式 Perm Space
  6. 运行时常量池属于方法区的一部分在方法区中进行分配
  7. 方法区是线程安全的。由于所有的线程都共享方法区,所以,方法区里的数据访问必须被设计成线程安全的。例如,同时有两个线程都访问方法区中的同一个类,而这个类还没有被装入 JVM ,那么只允许一个线程去装载它,而其它线程会被阻塞

运行时常量池

run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4). It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time. The run-time constant pool serves a function similar to that of a symbol table for a conventional programming language, although it contains a wider range of data than a typical symbol table.

基本概念

JVM 只有一个堆,且是被所有 JVM 线程共享的,类和数组等主要在堆中进行内存分配,堆的生命周期同样是与 JVM 互相绑定的。堆拥有以下特点:

  1. 堆是 Java 虚拟机锁管理内存中最大的一块,在虚拟机启动时创建,被所有线程共享
  2. Java 对象实例以及数组都在堆上分配
  3. 当堆无法满足内存分配需求时,将抛出 OOM 异常

虚拟机栈

  1. 虚拟机栈是一个线程执行的区域,保存着一个线程中方法的调用状态。换句话说,一个 Java 线程的运行状态,由一个虚拟机栈来保存,所以虚拟机栈肯定是线程私有的、独有的,随着线程的创建而创建
  2. 每一个线程执行的方法,为该栈中的栈帧,即每个方法的执行操作会对应一个栈帧
  3. 调用一个方法,就会向栈中压入一个栈帧;一个方法调用完成,就会把该栈帧从栈中弹出

image-1673510627413

以下异常情况与 Java 虚拟机堆栈相关联:

  • 栈帧数超过栈深会抛出 StackOverflowError 异常,如:无中断递归、无返回栈帧压入等
  • 如果 Java 虚拟机堆栈可以动态扩展,并且尝试扩展但没有足够的内存可用于实现扩展,或者如果没有足够的内存可用于为新线程创建初始 Java 虚拟机堆栈,则 Java 虚拟机将抛出 OutOfMemoryError 异常

栈帧

  1. 每个栈帧对应一个被调用的方法,可以理解为一个方法的运行空间
  2. 每个栈帧中包括局部变量表(Local Variables)、操作数栈(Operand Stack)、动态链接(Dynamic Linking)、方法返回地址(Return Address)和附加信息

理解栈帧

通过 javap 指令得到反编译的字节码文件中一个方法的流程代表一个栈帧,一个栈帧中存放了 jvm 的指令

public static int calc(int, int);
	Code:
		0: iconst_3  // 将int类型常量3压入操作数栈
		1: istore_0  // 将int类型值存入局部变量0
		2: iload_0   // 从局部变量0中装载int类型值到操作数栈
		3: iload_1   // 从局部变量1中装载int类型值到操作数栈
		4: iadd      // 执行int类型的加法
		5: istore_2  // 将int类型值存入局部变量2
		6: iload_2   // 从局部变量2中装载int类型值
		7: ireturn   // 从方法中返回int类型的数据

程序计数器

基本概念

一个 JVM 进程中有多个线程正在执行,而线程中的内容是否能够拥有执行权,是根据 CPU 调度来的。

加入线程 A 正在执行到某个地方,突然失去了 CPU 的执行权,切换到了线程 B,然后当线程 A 再获得 CPU 执行权的时候,就需要通过线程中维护的一个变量来记录线程执行到哪个位置。程序计数器具有如下特点:

  1. 程序计数器占用的内存空间很小,由于 Java 虚拟机的多线程是通过线程轮流切换的,并分配处理器执行时间的方式来实现的,在任意时刻,一个处理器只会执行一条线程中的指令。因此,为了线程切换后能够恢复到正确的位置,每条线程需要有一个独立的程序计数器(线程私有)
  2. 如果线程正在执行 Java 方法,则计数器记录的是正在执行的虚拟机字节码指令的地址
  3. 如果正在执行的是 Native 方法,则这个计数器为空

本地方法栈

基本概念

如果当前线程执行的方法是 Native 雷晓宁的,这些方法就会在本地方法栈中执行,主要通过 C/C++ 来执行。

3

评论区