Java假造机 - 步伐计数器和假造机栈

打印 上一主题 下一主题

主题 2163|帖子 2163|积分 6489

Java运行时数据区

首先介绍Java运行时数据之前,我们要相识,对于计算机来说,内存是非常重要的资源,因为内存是连接CPU与硬盘的桥梁,承载着操作体系与应用步伐的运行的基础。JVM在运行期间把它管理的内存分为若干个地区,有些地区是线程私有的,有些地区是共享的。
Java运行时数据区作为JVM在步伐实行过程中管理内存的焦点结构,重要包括方法区(存储类元数据、运行时常量池、静态变量)、堆(存放对象实例和数组,被全部线程共享且是垃圾回收的主地区)、假造机栈(每个线程私有,用于存储方法调用的栈帧,包含局部变量表、操作数栈及方法出口)、本地方法栈(支持Native方法调用)和步伐计数器(记录当火线程实行的字节码位置,确保多线程切换后能恢复实行)。其中,堆和方法区是线程共享的,而假造机栈、本地方法栈和步伐计数器为线程私有,共同协作实现Java步伐的内存分配、方法实行及多线程调理。

步伐计数器

步伐计数器(Program Counter Register)在JVM中可以当成当火线程所实行的字节码的行号指示器,在JVM的概念模子里面,字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要实行的字节码指令,它是步伐控制流的指示器。分支 、循环 、跳转 、异常处理 、线程恢复等都是依赖这个计数器来实现的。

假如步伐实行的是Java方法,计数器代表的是只在实行的假造机字节码的地址;假如实行的是本地方法,这个计数器的值为空(undefined)。此外,这个计数器地区是Java假造机规范的没有规定任何内存溢出的地方,步伐计数区既没有内存溢出,也没有垃圾回收。因为步伐计数器是很小的一块内存地区,几乎可以忽略不记,同时也是运行最快的地区。
为什么需要步伐计数器

因为CPU需要不停的切换各个线程,做完切换之后,需要知道接下来从哪里开始实行。通过使用步伐计数器生存了接下来要实行的地址,这样CPU切换过来之后就可以直接接着实行。
实行流程

  1. // 示例代码
  2. public class Demo {
  3.     public int test() {
  4.         int a = 10;
  5.         int b = 20;
  6.         int c = a + b;
  7.         String d = "abd";
  8.         System.out.println(d);
  9.         return d.length();
  10.     }
  11. }
复制代码
通过javap -c Demo.class反编译后:
  1. 0 bipush 10
  2. 2 istore_1
  3. 3 bipush 20
  4. 5 istore_2
  5. 6 iload_1
  6. 7 iload_2
  7. 8 iadd
  8. 9 istore_3
  9. 10 ldc #2 <abd>
  10. 12 astore 4
  11. 14 getstatic #9 <java/lang/System.out : Ljava/io/PrintStream;>
  12. 17 aload 4
  13. 19 invokevirtual #15 <java/io/PrintStream.println : (Ljava/lang/String;)V>
  14. 22 aload 4
  15. 24 invokevirtual #21 <java/lang/String.length : ()I>
  16. 27 ireturn
复制代码

假造机栈

假造机栈(Java Virtual Machine Stack)是JVM内存模子中与线程实行密切相关的焦点地区,用于存储方法调用的栈帧(Stack Frame)。它是线程私有的内存空间,每个线程在创建时都会分配一个独立的假造机栈,其生命周期与线程同等。以下从设计目标、焦点结构、运行机制到常见问题全面解析。
假造机栈作用

假造机栈的焦点功能是支持Java方法的调用与实行,具体包括:


  • 方法调用链管理:生存方法的调用顺序(如 main() → methodA() → methodB())。
  • 局部变量存储:存储方法内的基本范例变量、对象引用。
  • 操作数计算:提供临时数据存储空间(如算术运算的中心效果)。
  • 方法返回控制:记录方法实行完成后的返回地址。
假造机栈焦点结构

假造机栈由多个栈帧(Stack Frame)构成,每个栈帧对应一个方法的调用。栈帧包含以下焦点部分:

  • 局部变量表(Local Variables Table)
    作用:存储方法参数和方法内界说的局部变量。
    1. 结构:
    2.                 以变量槽(Slot)为最小单位,每个Slot占用32位(long和double占2个Slot)。
    3.                 索引从0开始,依次存放this(非静态方法)、方法参数、局部变量。
    4. 示例:
    复制代码
  1. public void demo(int a, String b) {
  2.     double c = 3.14;
  3.     Object d = new Object();
  4. }
复制代码
  1. 局部变量表结构:
复制代码


  • 操作数栈(Operand Stack)
    作用:生存计算过程中的临时数据(雷同CPU的寄存器)。
    特点:
    1. 深度在编译期确定(写入方法表的max_stack属性)。
    2. 通过iconst_1、iadd等字节码指令操作栈顶元素。
    复制代码
  1. int result = 1 + 2;
复制代码
  1. iconst_1  // 压入1
  2. iconst_2  // 压入2
  3. iadd      // 弹出1和2,相加后压入3
  4. istore_1  // 将3存储到局部变量表索引1
复制代码

  • 动态链接(Dynamic Linking)


  • 作用:将符号引用(如com/example/Demo.methodA)转换为直接引用(内存地址)。
  • 意义:支持多态特性(如接口方法、虚方法调用)。
  • 对比:

    • 静态解析:类加载阶段可确定的直接引用(如final方法)。
    • 动态链接:运行时才华确定(如重写方法)。


  • 方法返回地址(Return Address)
    作用:记录方法正常竣事或异常退出后的返回位置。
    两种返回方式:


  • 正常返回(return指令):步伐计数器恢复为调用者的下一条指令地址。
  • 异常退出:通过异常处理器表(Exception Table)确定跳转地址。
运行机制


  • 方法调用与栈帧压栈
    调用方法时:创建新栈帧并压入栈顶。
方法返回时:栈帧弹出,开释内存。

  • 栈溢出(StackOverflowError)
    触发条件:线程请求的栈深度凌驾JVM答应的最大值(如无穷递归)。
示例:
  1. public class StackOverflowDemo {
  2.     public static void main(String[] args) {
  3.         infiniteCall(); // 无限递归调用
  4.     }
  5.     static void infiniteCall() {
  6.         infiniteCall();
  7.     }
  8. }
复制代码
报错信息:
  1. Exception in thread "main" java.lang.StackOverflowError
复制代码

  • 栈大小配置
    参数:-Xss(如-Xss1m设置栈大小为1MB)。
默认值:不同JVM实现不同(HotSpot Linux x64默认1MB)。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

鼠扑

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表