news 2026/2/26 2:46:05

栈桢中引用对象是如何进行的?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
栈桢中引用对象是如何进行的?

要理解栈帧中引用对象的过程,首先需明确核心原则对象实例存储在堆中,栈帧仅存储指向堆对象的 “引用”(地址 / 句柄),栈帧通过这个引用间接操作堆中的对象。以下从栈帧结构、引用关联过程、访问逻辑、生命周期等维度详细拆解:

一、基础概念铺垫

  1. 栈帧(Stack Frame):JVM 为每个方法调用创建的栈元素,包含:
    • 局部变量表:存储方法的局部变量(包括对象引用、基本类型值);
    • 操作数栈:执行字节码时临时存放操作数(如对象引用、方法参数);
    • 动态链接:指向方法的符号引用(用于方法调用);
    • 返回地址:方法执行完后回到调用方的位置。
  2. 引用的本质:栈帧中存储的 “引用” 不是对象本身,而是两种形式(HotSpot 默认用第一种):
    • 直接指针:引用值是堆中对象的实际内存地址(主流实现);
    • 句柄:引用值指向 “句柄池” 中的句柄,句柄再指向对象的实例数据(堆)和类型数据(方法区 / 元空间)。

二、栈帧关联对象引用的核心流程(以new Object()为例)

以最简单的对象创建和引用赋值为例,拆解字节码层面的执行逻辑:

java

运行

public void test() { Object obj = new Object(); // 核心代码 }

对应的字节码(关键指令):

plaintext

0: new #2 // 创建Object实例(堆分配) 3: dup // 复制操作数栈顶的引用 4: invokespecial #1 // 调用Object的构造方法 7: astore_1 // 将引用存入局部变量表第1个slot 8: return // 方法返回
步骤 1:堆中创建对象(new指令)
  • JVM 执行new指令时,在堆中为Object分配内存,初始化对象头(Mark Word、类型指针等),但此时对象未执行构造方法(仅完成 “内存分配”);
  • new指令执行后,将对象的引用压入操作数栈(操作数栈顶现在是这个引用)。
步骤 2:执行构造方法(invokespecial指令)
  • dup指令复制操作数栈顶的引用(因为invokespecial会消耗引用,复制后保留一份用于后续赋值);
  • invokespecial指令弹出操作数栈中的引用,通过该引用找到堆中的对象,执行构造方法完成对象初始化。
步骤 3:引用存入局部变量表(astore_1指令)
  • 操作数栈顶仍保留一份对象引用,astore_1指令将该引用从操作数栈弹出,存入当前栈帧的局部变量表第 1 个 slotthis指针占第 0 个 slot);
  • 此时,栈帧的局部变量表中obj变量持有了堆中Object实例的引用,后续可通过该引用操作对象。

三、通过引用访问对象的核心操作

栈帧中的引用是操作堆对象的唯一入口,常见操作(字段访问、方法调用)的底层逻辑如下:

1. 访问实例字段(getfield/putfield指令)

java

运行

obj.toString(); // 先获取obj的引用,再访问toString方法;若给字段赋值则用putfield
  • 读字段(getfield)
    1. 将对象引用压入操作数栈;
    2. 执行getfield指令,根据引用找到堆中的对象,再通过常量池中的字段偏移量,读取对象的字段值;
    3. 将字段值压入操作数栈,供后续使用。
  • 写字段(putfield)
    1. 将对象引用、要写入的字段值依次压入操作数栈;
    2. 执行putfield指令,通过引用定位堆对象,将值写入对应字段的内存位置。
2. 调用实例方法(invokevirtual/invokeinterface指令)

java

运行

obj.toString();
  • 步骤 1:将对象引用、方法参数(无参则仅压引用)压入操作数栈;
  • 步骤 2:执行invokevirtual指令,通过引用的类型指针找到对象的类元信息,再通过方法表(vtable)确定要执行的具体方法(处理多态);
  • 步骤 3:为该方法创建新栈帧,将对象引用作为this指针存入新栈帧的局部变量表第 0 个 slot;
  • 步骤 4:执行方法逻辑,完成后销毁栈帧,返回结果(若有)。

四、栈帧中引用的生命周期

  1. 栈帧创建阶段:局部变量表初始化,对象引用变量默认值为null(未赋值时);
  2. 方法执行阶段:通过字节码(如astore_<n>)为引用赋值,或通过getfield/invokevirtual操作引用;
  3. 栈帧销毁阶段:方法执行完毕(return),栈帧出栈,局部变量表中的引用被销毁;
    • 若堆中的对象无其他引用(如其他栈帧的引用、静态变量引用),则该对象会被 GC 标记为 “可回收”,等待垃圾回收。

五、特殊场景补充

1. 不同引用类型的影响(强 / 软 / 弱 / 虚)

栈帧中存储的引用类型(JDK 提供的四种引用)会影响 GC 对堆对象的处理逻辑:

  • 强引用(默认):如Object obj = new Object(),只要引用存在,堆对象永不被 GC(即使 OOM);
  • 软引用SoftReference):栈帧存储SoftReference的引用,堆中目标对象在内存不足时才会被 GC(用于缓存);
  • 弱引用WeakReference):栈帧存储WeakReference的引用,GC 时只要发现目标对象只有弱引用,立即回收(如ThreadLocal);
  • 虚引用PhantomReference):仅用于跟踪对象回收,必须配合引用队列,栈帧中无法通过该引用获取目标对象。
2. 逃逸分析的优化(栈上分配)

若 JVM 通过逃逸分析判定对象不会逃逸出方法(仅在当前方法内使用),会触发标量替换优化:

  • 不再在堆中创建对象,而是将对象的字段直接存储在栈帧的局部变量表中;
  • 此时栈帧中无 “引用”,直接操作字段值,方法结束后栈帧销毁,字段值也随之释放(无需 GC)。这是 JVM 的优化场景,并非默认的 “引用访问” 逻辑。

六、核心总结

  1. 栈帧不存对象实例,仅存指向堆对象的引用(地址 / 句柄);
  2. 引用的核心操作流程:堆创建对象 → 引用入操作数栈 → 构造方法初始化 → 引用存入局部变量表 → 通过引用访问字段 / 调用方法;
  3. 栈帧销毁后,引用失效,堆对象若无其他引用则被 GC 回收;
  4. 引用类型(强 / 软 / 弱 / 虚)决定 GC 对堆对象的回收策略,逃逸分析可跳过 “引用” 直接在栈上存储对象字段。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/19 3:14:40

EcoVadis 评级划分

EcoVadis 评级按 0 - 100 分总分划分为铂金、金、银、铜、无等级五个等级。2024 年后等级对应标准为&#xff1a;铂金&#xff08;前 1%&#xff0c;81 - 100 分&#xff09;金牌&#xff08;前 5%&#xff0c;73 - 80 分&#xff09;银牌&#xff08;前 15%&#xff0c;66 - 7…

作者头像 李华
网站建设 2026/2/23 10:26:31

FLUX.1 Kontext:120亿参数开源模型如何重塑数字创意工作流

FLUX.1 Kontext&#xff1a;120亿参数开源模型如何重塑数字创意工作流 【免费下载链接】FLUX.1-Kontext-dev 项目地址: https://ai.gitcode.com/hf_mirrors/black-forest-labs/FLUX.1-Kontext-dev 开篇思考&#xff1a;当AI遇见精准图像编辑 在数字内容创作爆发式增长…

作者头像 李华
网站建设 2026/2/24 12:22:25

Kerl终极指南:快速掌握Erlang版本管理全流程

Kerl终极指南&#xff1a;快速掌握Erlang版本管理全流程 【免费下载链接】kerl Easy building and installing of Erlang/OTP instances 项目地址: https://gitcode.com/gh_mirrors/ke/kerl 还在为不同Erlang项目需要不同版本而烦恼&#xff1f;手动编译时遭遇依赖问题&…

作者头像 李华
网站建设 2026/2/23 15:59:30

Share.js 终极指南:5分钟实现网站社交分享功能

Share.js 终极指南&#xff1a;5分钟实现网站社交分享功能 【免费下载链接】share.js overtrue/share.js 是一个用于实现网站内分享的 JavaScript 库。适合在网站开发中使用&#xff0c;提供多种分享方式和自定义选项。特点是提供了简洁的 API、丰富的分享平台和良好的兼容性。…

作者头像 李华
网站建设 2026/1/29 11:35:22

51CTO-OpenGL渲染引擎-设计与实践

在现代图形渲染引擎的开发中&#xff0c;OpenGL 作为一种广泛应用的图形渲染接口&#xff0c;提供了强大的功能和灵活性。然而&#xff0c;如何在复杂的场景中实现高效且精准的渲染效果&#xff0c;始终是图形开发人员面临的一项挑战。深度测试&#xff08;Depth Testing&#…

作者头像 李华
网站建设 2026/2/25 12:25:33

使用Monkey命令做简单的安卓APP稳定性测试

Monkey是Android SDK提供的一个命令行工具&#xff0c;可以简单方便的发送伪随机的用户事件流&#xff0c;对Android APP做压力&#xff08;稳定性&#xff09;测试。主要是为了测试app是否存在无响应和崩溃的情况。 Monkey 是SDK中附带的一个工具&#xff0c;所有的事件都是随…

作者头像 李华