JVM局部变量表和操作数栈的内存布局

局部变量表和操作数栈

首先看一段Java源码

java 复制代码
public class Add_Sample{
    public int add(int i, int j){
        int k = 100;
        int result = i + j + k;
        return result;
    }
    public static void main(String[] args){
        int result = new Add_Sample().add(10,20);
        System.out.println(result);
    }
}

使用javac Add_Sample.java进行编译

使用javap -v Add_Sample查看生成的相关函数的字节码

复制代码
public int add(int, int);
  Code:
   Stack=2, Locals=5, Args_size=3
   0:   bipush  100
   2:   istore_3
   3:   iload_1
   4:   iload_2
   5:   iadd
   6:   iload_3
   7:   iadd
   8:   istore  4
   10:  iload   4
   12:  ireturn
  LineNumberTable:
   line 3: 0
   line 4: 3
   line 5: 10


public static void main(java.lang.String[]);
  Code:
   Stack=3, Locals=2, Args_size=1
   0:   new     #2; //class Add_Sample
   3:   dup
   4:   invokespecial   #3; //Method "<init>":()V
   7:   bipush  10
   9:   bipush  20
   11:  invokevirtual   #4; //Method add:(II)I
   14:  istore_1
   15:  getstatic       #5; //Field java/lang/System.out:Ljava/io/PrintStream;
   18:  iload_1
   19:  invokevirtual   #6; //Method java/io/PrintStream.println:(I)V
   22:  return

如何查看局部变量表和操作数栈的深度

这里可以查看add函数和main函数的Code下面的值,以add函数为例

复制代码
public int add(int, int);
  Code:
   Stack=2, Locals=5, Args_size=3

这里可以看到Stack=2,表示操作数栈的深度是2

Locals=5,表示局部变量表的个数是5

Args_size=3,表示参数个数为3。这里相比于形参多了一个参数,这个参数就是该函数的this指针。

局部变量表和操作数栈如何配合完成计算

回到add函数的字节码,main函数将10和20作为参数传递给add函数。所以本地变量表的前3个元素分别填入了函数参数。

assembly 复制代码
0:   bipush  100
2:   istore_3
3:   iload_1
4:   iload_2
5:   iadd
6:   iload_3
7:   iadd
8:   istore  4
10:  iload   4

上述字节码的执行步骤如下

经过上述步骤就完成了计算过程

局部变量表和操作数栈在内存中的实际布局

openjdk中,其实际布局分别位于解释栈的高地址和低地址,用locals寄存器和sp寄存器进行定位。在x64架构中,rlocalsr14sprsp

如果要获得第2个参数,那么只需要执行将locals的地址加上对应的偏移即可获得。

举例istore字节码在x64的实现

assembly 复制代码
locals_index(rbx);//将字节码指令中的index值放入rbx
__ movl(iaddress(rbx), rax);//将本地变量表中的index值放入rax。为了加快速度,在x86中默认将rax寄存器作为栈顶

如果要执行压栈操作,只需要将sp减去对应的值并将值放入sp所在内存即可。这里不举例了,因为在openjdk的解释器实现时并不是简单的往内存压栈,而是结合了栈顶缓存实现。

总结

局部变量表(locals)包括了函数内部的临时变量和形参,另外还包括了当前函数的this指针

操作数栈实现了Java虚拟机的栈式操作

openjdk的实现中,局部变量表位于解释栈的高地址处,用locals寄存器定位局部变量表并根据偏移值获取值;操作数栈位于解释栈的低地址,用sp寄存器定位实现字节码逻辑。

相关推荐
lulu121654407810 分钟前
OpenRouter Fusion 多模型融合架构深度拆解:预算级模型组团打平 Fable 5,多模型协作才是 AGI 的正确打开方式?
java·人工智能·架构·ai编程·agi
雨辰AI15 分钟前
生产级实测:SpringBoot3 + 达梦数据库接口从 200ms 优化至 20ms 完整调优指南
java·数据库·spring boot·后端·政务
(Charon)44 分钟前
【C++ 面试高频:内存管理、RAII 和智能指针详解】
java·开发语言·word
凡人叶枫1 小时前
Effective C++ 条款39:明智而审慎地使用 private 继承
java·数据库·c++·嵌入式开发
轻刀快马1 小时前
跨越软硬件的共鸣(二):从 Cache 写策略看 Redis 与 DB 的一致性博弈
java·开发语言·redis·计算机组成原理
折哥的程序人生 · 物流技术专研1 小时前
Java 23 种设计模式:从踩坑到精通 | 装饰器模式 —— 比继承更灵活的扩展方式,你用过吗?
java·装饰器模式·java面试·结构型模式·java设计模式·javaio·从踩坑到精通
lili00121 小时前
2026 企业 AI 选型新范式:OpenRouter Fusion 证明多模型融合性价比远超单模型,企业该如何重构技术栈? - 微元算力(weytoken)
java·人工智能·python·重构·ai编程
shushangyun_1 小时前
汽车服务行业B2B平台+AI解决方案哪家专业:2026年最新测评
java·运维·网络·数据库·人工智能·汽车
A.说学逗唱的Coke2 小时前
【大模型专题】Spring AI Alibaba × Skill 整合实战:让 AI 真正“会干活
java·人工智能·spring
大黄说说2 小时前
深入理解 Go 协程 Goroutine:并发编程的核心精髓
java·数据库·python