NOP
Java 虚拟机的操作码在今天的 JVM 中是否有任何实际用途?如果是这样,在哪些情况下NOP
会在字节码中生成 s?
我什至有兴趣看到一个用NOP
s 编译成字节码的 Java 代码示例。
更新
BCEL 的MethodGen类说,
在生成代码时,可能需要插入 NOP 操作。
我猜其他字节码生成库也在同一条船上,正如接受的答案中所指出的那样。
一些NOP
字节码用例用于由Apache BCEL、ASM、FindBugs、PMD等class
工具执行的文件转换、优化和静态分析。Apache BCEL 手册涉及用于分析和优化目的的一些用途。NOP
JVM 可以使用NOP
字节码进行 JIT 优化,以确保处于同步安全点的代码块正确对齐以避免错误共享。
至于一些使用 JDKjavac
编译器编译的包含NOP
字节码的示例代码,这是一个有趣的挑战。但是,我怀疑编译器会生成任何class
包含NOP
字节码的文件,因为the bytecode instruction stream is only single-byte aligned
. 我很想看到这样的例子,但我自己想不出。
这是我一直在研究的一些代码的示例,其中 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)));
}
}
equals(Object) 方法的翻译字节码
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;
}
我不确定为什么要插入这些。我只是希望它们不会对性能产生不利影响。
通常不会为处理器管道优化添加任何操作。我不确定 Java 目前在多大程度上使用它们。
来自维基百科:
NOP 最常用于时序目的,强制内存对齐,防止危险,占用分支延迟槽,或作为占位符,在程序开发的后期由活动指令替换(或替换已删除的指令)重构将是有问题的或耗时的)。在某些情况下,NOP 可能会产生轻微的副作用;例如,在 Motorola 68000 系列处理器上,NOP 操作码会导致流水线同步。