2012-05-02 51 views
16

在當今的JVM中,Java虛擬機的NOP操作碼是否有任何實際用途?如果是這樣,那麼在字節碼中會產生哪些場景NOP用於JVM字節碼的NOP是什麼?

我甚至有興趣看到一個編碼爲NOP的字節碼的Java代碼的例子。


更新

BCEL的MethodGen班說,

在生成代碼,可能需要插入NOP操作。

我在猜測其他的字節碼生成庫在同一條船上,正如在接受的答案中指出的那樣。

+0

通常在調試代碼中使用它來允許某些不轉換爲字節碼的斷點,如'{'。 – vcsjones

+0

你的意思是說,當使用'javac -g'編譯Java文件時,這會出現在字節碼中? – jbranchaud

+0

我不相信'javac'會這樣做。但其他編譯器和調試器可以使用該功能。 – vcsjones

回答

12

一些NOP字節碼的使用情況是class文件變換,優化和工具進行靜態分析,如Apache BCELASMFindBugsPMD等對NOP一些使用Apache BCEL manual觸摸進行分析和優化的目的。

JVM可能使用NOP字節碼進行JIT優化,以確保處於同步安全點的代碼塊正確對齊以避免false sharing

對於使用包含NOP字節碼的JDK javac編譯器編譯的一些示例代碼,這是一個有趣的挑戰。不過,我懷疑編譯器會自the bytecode instruction stream is only single-byte aligned以後生成包含NOP字節碼的任何class文件。我會很好奇看到這樣一個例子,但我想不出自己。

1

通常不會爲操作系統優化添加操作。我不確定Java目前在多大程度上使用它們。

Wikipedia

甲NOP最常用於定時目的,以迫使存儲器 對準,以防止危害,以佔據分支延遲槽中,或作爲 佔位符被替換通過活動指令稍後在程序 開發中(或者當重構將 有問題或耗時時替換移除的指令)。在某些情況下,NOP可能有輕微的副作用;例如,在Motorola 68000系列處理器上, NOP操作碼會導致管道同步。

+6

這在物理機器操作碼中是有意義的,但是對於虛擬機器操作碼會有什麼用? –

+0

我很欣賞答案,但這個問題是關於JVM的非常具體。 – jbranchaud

2

下面是一些代碼,我已經工作的示例,其中,其中放置到字節碼(如由字節碼展示臺爲Eclipse看去)NOP指令

原始代碼

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))); 
    } 
} 

等於(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; 
} 

我不確定爲什麼要插入這些字節碼。我只希望他們不會對性能產生負面影響。

+3

沒有'nop',這只是您使用的Bytecode Visualizer中的一個錯誤。 'invokedynamic'指令由五個字節組成,最後兩個字節爲每個規範零。顯然,Bytecode Visualizer並不知道這一點,並假定'invokedynamic'指令只有三個字節,並將兩個零字節誤解爲'nop'指令。請參閱[JVM規範invokedynamic](https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic)。 – Holger

+0

我想這是有道理的。我在等待更新Bytecode Visualizer for Eclipse Neon。也許我們應該告訴開發者。 – HesNotTheStig