在今天的JVM中,Java虚拟机的NOP
操作码有什么实际用途吗?如果有,生成字节码时会出现哪些NOP
场景?
我甚至想看一下编译成带有NOP
的字节码的Java代码示例。
更新
BCEL的MethodGen类说:
在生成代码时,可能需要插入NOP操作。
我猜其他字节码生成库也是如此,正如被接受的答案所指出的那样。
一些NOP
字节码用于由工具执行的Apache BCEL,ASM,FindBugs,PMD等进行的类
文件转换,优化和静态分析。 Apache BCEL手册涉及了一些使用NOP
进行分析和优化的用途。
JVM可能会使用NOP
字节码进行JIT优化,以确保在同步安全点处的代码块被正确对齐,以避免false sharing(伪共享)。
javac
编译器编译的一些示例代码,其中包含NOP
字节码,这是一个有趣的挑战。然而,我怀疑编译器将生成任何包含NOP
字节码的class
文件,因为字节码指令流仅单字节对齐
。我很想看到这样的例子,但我自己想不出来。我是一名有用的助手,可以为您进行文本翻译。
这是我正在处理的一些代码示例,其中nop指令被放置到字节码中(在Eclipse的Bytecode Visualizer中查看)
原始代码:
public abstract class Wrapper<T extends Wrapper<T,E>,E>
implements Supplier<Optional<E>>, Consumer<E>
{
/** The wrapped object. */
protected Optional<E> inner;
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
/**
* A basic equals method that will compare the wrapped object to
* whatever you throw at it, whether it is wrapped or not.
*/
@Override
public boolean equals(final Object that)
{
return this==that
||LambdaUtils.castAndMap(that,Wrapper.class,afterCast
-> inner.equals(afterCast.inner))
.orElseGet(()
-> LambdaUtils.castAndMap(that,Optional.class,afterCast
-> inner.equals(afterCast))
.orElseGet(()
-> Optional.ofNullable(that).map(thatobj
-> that.equals(inner.get()))
.orElseGet(()
-> false)));
}
}
public boolean equals(java.lang.Object arg0) {
/* L27 */
0 aload_0; /* this */
1 aload_1; /* that */
2 if_acmpeq 36;
/* L28 */
5 aload_1; /* that */
6 ldc 1;
8 aload_0; /* this */
9 invokedynamic 29; /* java.util.function.Function apply(ext.cat.wcutils.collections.Wrapper arg0) */
12 nop;
13 nop;
14 invokestatic 30; /* java.util.Optional ext.cat.wcutils.util.LambdaUtils.castAndMap(java.lang.Object arg0, java.lang.Class arg1, java.util.function.Function arg2) */
/* L30 */
17 aload_0; /* this */
18 aload_1; /* that */
19 invokedynamic 39; /* java.util.function.Supplier get(ext.cat.wcutils.collections.Wrapper arg0, java.lang.Object arg1) */
22 nop;
23 nop;
24 invokevirtual 40; /* java.lang.Object orElseGet(java.util.function.Supplier arg0) */
27 checkcast 46; /* java.lang.Boolean */
30 invokevirtual 48; /* boolean booleanValue() */
/* L37 */
33 ifne 5;
/* L27 */
36 iconst_0;
37 ireturn;
38 iconst_1;
39 ireturn;
}
nop
指令。invokedynamic
指令由五个字节组成,其中最后两个字节根据规范应该为零。显然,该字节码可视化工具不知道这一点,并假设 invokedynamic
指令只有三个字节,并将这两个零字节误解为 nop
指令。参考 JVM Spec invokedynamic。 - Holger无操作指令通常用于处理器流水线优化。我不确定Java目前在多大程度上使用它们。
来自维基百科:
NOP最常用于计时目的,强制内存对齐,防止危险,占用分支延迟槽,或作为占位符,在程序开发中稍后替换为活动指令(或在重构会很困难或耗时的情况下替换已删除的指令)。在某些情况下,NOP可能会产生轻微的副作用;例如,在Motorola 68000系列处理器上,NOP操作码会导致流水线同步。
{
。 - vcsjonesjavac -g
编译Java文件时,您的意思是这会出现在字节码中吗? - jbranchaudjavac
会这样做。但其他编译器和调试器可能会利用那个功能。 - vcsjones