当前位置: 首页 > 面试题库 >

什么是堆栈映射框架

胡俊贤
2023-03-14
问题内容

最近,我一直在寻找Java虚拟机规范(JVMS),以试图更好地理解使我的程序正常工作的原因,但是我找到了一段我不太了解的部分…

第4.7.4节介绍了
StackMapTable 属性,在该节中,文档介绍了有关堆栈映射框架的详细信息。问题是它有点罗word,我以身作则,学得最好。不读书。

我知道第一个堆栈映射框架是从方法描述符派生的,但是我不知道如何(应该在这里进行解释。)而且,我也不完全理解堆栈映射框架的作用。我以为它们类似于Java中的块,但似乎您不能在彼此内部拥有堆栈映射框架。

无论如何,我有两个具体问题:

  • 堆栈贴图框架做什么?
  • 如何创建第一个堆栈贴图框架?

一个普遍的问题:

  • 有人可以提供比JVMS中给出的解释少一些冗长,更容易理解的解释吗?

问题答案:

Java要求对所有加载的类进行验证,以维护沙箱的安全性并确保代码可以安全地优化。注意,这是在字节码级别上完成的,所以验证并 不会
验证了Java的不变量 的语言 ,它只是验证字节码,根据字节码的规则是有道理的。

除其他外,字节码验证可确保指令格式正确,所有跳转均指向方法中的有效指令,以及所有指令均以正确类型的值进行操作。最后一个是堆栈映射进入的位置。

问题是字节码本身不包含任何显式类型信息。类型是通过数据流分析隐式确定的。例如,iconstest指令创建一个整数值。如果将其存储在插槽1中,则该插槽现在具有一个int。如果控制流从存储浮点数的代码合并,则该插槽现在被认为具有无效的类型,这意味着在覆盖该值之前,您无法再对该值进行任何操作。

从历史上看,字节码验证程序使用这些数据流规则来推断所有类型。不幸的是,不可能通过字节码在一次线性传递中推断出所有类型,因为向后跳转可能会使已经推断出的类型无效。经典的验证程序通过遍历代码直到一切都停止更改来解决此问题,这可能需要多次通过。

但是,验证会使Java中的类加载变慢。Oracle决定通过添加一个新的,更快的验证程序来解决此问题,该验证程序可以一次性验证字节码。为此,他们
需要从Java 7 (Java 6处于过渡状态) 开始的所有新类,
以携带有关其类型的元数据,以便可以通过一次验证字节码。由于字节码格式本身无法更改,因此此类型信息分别存储在名为的属性中StackMapTable

简单地在代码中的每个点存储每个值的类型显然会占用很多空间,并且非常浪费。为了使元数据更小,更有效,他们决定 只列出作为跳转目标的位置处的类型
。如果您考虑一下,这是您唯一一次需要额外信息来进行单次通过验证的情况。在跳转目标之间,所有控制流都是线性的,因此您可以使用旧的推理规则来在两个位置之间的类型中进行推理。

显式列出类型的每个位置称为堆栈映射框架。该StackMapTable属性按顺序包含帧列表,尽管通常将它们表示为与前一帧的差异,以减小数据大小。如果该方法中没有框架(当控制流从不加入时会发生(即CFG是树)),则可以完全省略StackMapTable属性。

因此,这是StackMapTable如何工作以及为什么添加它的基本思想。最后一个问题是如何创建隐式初始帧。答案当然是,在方法开始时,操作数堆栈为空,并且局部变量槽具有由方法参数类型给定的类型,这些方法参数由方法分拆器确定。

如果您习惯使用Java,则方法参数类型在字节码级别上的工作方式会有一些细微的差异。首先,虚拟方法将隐式this作为第一个参数。二是booleanbytechar,并short不会在字节码级别存在。取而代之的是,它们都被实现为幕后的整数。



 类似资料:
  • 我理解JVM如何从OS提供的可用本机堆中创建java堆。

  • 问题内容: 我正在阅读有关JVM体系结构的信息。今天,我了解了操作数堆栈的概念。根据一篇文章: 在字节码指令执行期间使用操作数堆栈,其方式与在本机CPU中使用通用寄存器的方式类似。 我不明白:操作数堆栈到底是什么,以及它在jvm中如何工作? 问题答案: 这是各种单个字节码操作如何获取其输入以及它们如何提供其输出的方式。 例如,考虑将两个s相加的运算。要使用它,您将两个值压入堆栈,然后使用它: 现在

  • 蜻蜓映射是一款动态域名解析软件,外网通过蜻蜓映射域名随时随地访问到内网搭建服务。 蜻蜓映射是内网穿透,端口映射的软件服务商。支持HTTP、HTTPS、TCP、UDP、等多种协议。 无需设置路由器端口映射即可外网访问内网服务器。适用于远程桌面、 远程服务器、远程办公、游戏联机、微信开发调试等内网穿透场景。蜻蜓映射端口映射官网 如何使用蜻蜓映射 注册账号 下载客户端并登录 添加映射

  • 主要内容:进栈和出栈,栈的具体实现,栈的应用同 顺序表和 链表一样, 栈 也是用来存储逻辑关系为 "一对一" 数据的线性存储结构,如图 1 所示。 图 1 栈存储结构示意图 从图 1 我们看到,栈存储结构与之前所学的线性存储结构有所差异,这缘于栈对数据 "存" 和 "取" 的过程有特殊的要求: 栈只能从表的一端存取数据,另一端是封闭的,如图 1 所示; 在栈中,无论是存数据还是取数据,都必须遵循"先进后出"的原则,即最先进栈的元素最后出栈。

  • 我正在阅读http://www.realworldtech.com/sandy-bridge/,我在理解一些问题时遇到了一些问题: 对于桑迪·布里奇(和P4),英特尔仍然使用罗布这个术语。但是,关键是要理解,在这种情况下,它只引用飞行中uops的状态数组 实际上是什么意思?请说清楚。

  • 问题内容: 我目前有一个使用filebeat作为日志发送程序的体系结构,该结构将日志发送到日志存储索引器实例,然后发送到AWS中的托管elasticsearch。由于存在持续的TCP连接,因此我无法使用AWS ELB多个日志存储索引器实例进行负载平衡,因为文件信号始终会选择这些实例并将其发送到那里。所以我决定使用redis。现在,看到扩展redis并使之在ELK堆栈中具有高可用性组件是多么困难,我