为什么 JVM 同时具有“invokespecial”和“invokestatic”操作码?

2024-04-24

两条指令都使用静态而不是动态调度。似乎唯一的实质性区别是invokespecial始终将一个对象作为其第一个参数,该对象是分派方法所属类的实例。然而,invokespecial实际上并没有把物体放在那里;编译器负责通过在发出之前发出适当的堆栈操作序列来实现这一点invokespecial。所以更换invokespecial with invokestatic不应该影响运行时堆栈/堆的操作方式——尽管我预计它会导致VerifyError因违反规范。

我很好奇制定两条基本上执行相同操作的不同指令背后的可能原因。我看了一下OpenJDK解释器的源码,好像是这样invokespecial and invokestatic处理方式几乎相同。拥有两条单独的指令是否有助于 JIT 编译器更好地优化代码,或者是否有助于类文件验证器更有效地证明某些安全属性?或者这只是 JVM 设计中的一个怪癖?


免责声明:很难确定,因为我从未阅读过有关此问题的明确 Oracle 声明,但我几乎认为原因如下:

当您查看 Java 字节码时,您可以对其他指令提出同样的问题。为什么验证者会在推两个时阻止你ints 在堆栈上并将它们视为单个long就在之后? (尝试一下,它会阻止你。)你可能会说,通过允许这样做,你可以用更小的指令集表达相同的逻辑。 (进一步来说,一个字节不能表达太多的指令,因此 Java 字节代码集应该尽可能地减少。)

当然,理论上你不需要字节码指令来推送ints and longs 到堆栈,你是对的,你不需要两条指令INVOKESPECIAL and INVOKESTATIC为了表达方法调用。方法由其唯一标识方法描述符(名称和原始参数类型)并且您无法在同一类中同时定义具有相同描述的静态和非静态方法。为了验证字节码,Java编译器必须检查目标方法是否是static尽管如此。

Remark:这与v6ak的答案相矛盾。但是,非静态方法的方法描述符不会更改为包括对this.getClass()。因此,Java 运行时始终可以从假设的方法描述符中推断出适当的方法绑定。INVOKESMART操作说明。请参阅 JVMS §4.3.3。

理论就讲这么多。然而,两种调用类型所表达的意图却截然不同。请记住,Java 字节码应该由除 Java 之外的其他工具使用javac也可以创建 JVM 应用程序。通过字节码,这些工具生成的代码比 Java 源代码更类似于机器代码。但仍然是相当高的水平。例如,字节代码仍然被验证并且字节代码在编译为机器代码时被自动优化。然而,字节码是一种抽象,故意包含一些冗余,以便使meaning字节码更加明确。就像 Java 语言对相似的事物使用不同的名称以使语言更具可读性一样,字节码指令集也包含一些冗余。另一个好处是,验证和字节码解释/编译可以加速,因为方法的调用类型并不总是需要推断,而是在字节码中明确说明。这是可取的,因为验证、解释和编译都是在运行时完成的。

作为最后的轶事,我应该提到类的静态初始值设定项<clinit>没有被标记static在 Java 5 之前。在这种情况下,静态调用也可以通过方法名称来推断,但这会导致更多的运行时开销。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 JVM 同时具有“invokespecial”和“invokestatic”操作码? 的相关文章

  • GC过多时如何更快OOM? [复制]

    这个问题在这里已经有答案了 有时 我的 JVM 会耗尽内存 但我可以从中恢复 或 heapDumpOnOOM 和调试 的 OOMing 它往往会在 GC 中颠簸数小时 然后抛出内存不足 这本质上与 未回答的 问题相同 如何配置 Java G
  • 为什么通用列表的声明存在差异?

    我想声明两个列表 首先是一个整数列表 我将其声明为 List
  • Neo4j cpu 卡在 GC 上

    突然间 工作了一个月后 CPU 几乎没有使用 1 到 5 之间 neo4j 服务器在垃圾收集时 cpu 占用率达到 100 我在 ubuntu 4 处理器服务器上运行 neo4j entherprise 2 0 3 未嵌入 这是我的 neo
  • JVM跳转指令的偏移量怎么会是32768呢?

    在写一个回答有关 JVM 字节码偏移量的问题 https stackoverflow com a 30240357 3182664 我注意到 javac 的行为和生成的类文件中有一些我无法解释的内容 当编译这样的类时 class FarJu
  • G1 GC 单个、非常长的年轻 GC 发生且 ParallelGCThreads=1

    I set ParallelGCThreads 1并使用G1 GC 所有其他JVM设置为默认设置 我跑PageRank在 Spark 1 5 1 上 有两个 EC2 节点 每个节点有 100 GB 堆 我的堆使用情况图如下 红色区域 年轻代
  • 以编程方式设置最大 Java 堆大小

    有没有办法以编程方式设置最大 java 堆大小而不是作为 vm 参数 就像是 System getProperties put
  • 内存中的方法表示是什么?

    在思考一下 Java C 编程时 我想知道属于对象的方法如何在内存中表示 以及这一事实如何涉及多线程 是为内存中的每个对象单独实例化一个方法还是执行 同一类型的所有对象共享该方法的一个实例 如果是后者 执行线程如何知道哪个对象是 要使用的属
  • 使用 Java 代理将类添加到类路径

    我正在使用 Java Agent 和 Javassist 向某些 JDK 类添加一些日志记录 本质上 当系统加载一些 TLS 类时 Javassist 会向它们添加一些额外的字节码 以帮助我调试一些连接问题 考虑到此类包含在代理 jar 中
  • Scala 泛型 - 为什么我无法在泛型类中创建参数化对象?

    我目前正在学习scala 为什么此代码不起作用 class GenClass T var d T var elems List T Nil def dosom x T var y new T y 我得到 错误 需要类类型 但找到了 T 代替
  • Jprofile可以连接到docker中运行的JVM

    我是 JProfiler 的新手 我最近遇到了一个问题 我的Java应用程序在docker中运行 这意味着JVM在docker中运行 但我的jprofile安装在主机上 我知道 jprofiler 必须连接到 JVM 那么 jprofile
  • 当 Java 中的集合超出容量时会发生什么?

    我有一个服务 它将所有对其进行的调用暂存在内存中 因为我们不想丢失数据 同时我们需要该服务因任何外部依赖项 例如数据库 而失败 然后 这些分阶段的调用会在后台例行接收和处理 如果出于任何原因 如果调用太多并且内存不足 我们就需要警惕 所以
  • 我的代码中出现内存不足异常

    作为 Oracle 数据库压力测试的一部分 我正在长时间运行代码并使用 java 版本 1 4 2 简而言之 我正在做的是 while true Allocating some memory as a blob byte data new
  • 如何解密Lua字节码?

    早上好 我正在尝试破译 Moon 字节码 但我无法以任何方式 有人可以帮助我吗 我有这个 例如 code 27 76 117 97 81 0 1 4 4 4 8 0 如何将此字节码解密为文本 我已经在这里搜索 http www asciit
  • HotSpot使用的Mark-Compact算法是什么?

    当阅读 Mark Compact 章节时垃圾收集手册 https rads stackoverflow com amzn click com 1420082795 提出了一系列替代方案 但其中大多数看起来很旧 理论上 例如 2 指压缩和 L
  • 启用JConsole远程监控是否会影响生产中的系统性能?

    Oracle Sun 说只要不在生产环境中本地运行就可以吗 http download oracle com javase 1 5 0 docs guide management jconsole html http download or
  • 字节码相对于本机代码有哪些优点? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 从内存中获取Java类字节码(经过多次转换)

    我正在为 Minecraft 开发一个 coremod 并在加载许多类时对其进行转换 然而问题是 有多个 coremod 也转换了与我相同的类 并且我遇到了一些我想研究的奇怪行为 那么问题来了 经过多次转换后的字节码如何检查呢 当我转换它时
  • Scala 对大数的阶乘有时会崩溃,有时不会

    以下程序经过编译和测试 有时返回结果 有时充满屏幕 java lang StackOverflowError at scala BigInt apply BigInt scala 47 at scala BigInt equals BigI
  • 如何判断我是在 64 位 JVM 还是 32 位 JVM 中运行(在程序内)?

    如何判断应用程序运行的 JVM 是 32 位还是 64 位 具体来说 我可以使用哪些函数或属性来在程序中检测到这一点 对于某些版本的 Java 您可以使用标志从命令行检查 JVM 的位数 d32 and d64 java help d32
  • 字节码和位码有什么区别[重复]

    这个问题在这里已经有答案了 可能的重复 LLVM 和 java 字节码有什么区别 https stackoverflow com questions 454720 what are the differences between llvm

随机推荐