【问题标题】:How to decompile volatile variable in Java?如何在 Java 中反编译 volatile 变量?
【发布时间】:2013-06-03 22:35:06
【问题描述】:

有人告诉我volatile 关键字可以在变量的写操作之前添加内存屏障。所以我写了代码:

public class Test {
    private Object o;

    public Test() {
        this.o = new Object();
    }

    private volatile static Test t;

    public static void createInstance() {
        t = new Test();             // volatile would insert memory barrier here.
    }

    public static void main(String[] args) throws Exception {
        Test.createInstance();
    }
}

然后反编译:

Compiled from "Test.java"
public class Test extends java.lang.Object{
public Test();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   new #2; //class java/lang/Object
   8:   dup
   9:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   12:  putfield    #3; //Field o:Ljava/lang/Object;
   15:  return

public static void createInstance();
  Code:
   0:   new #4; //class Test
   3:   dup
   4:   invokespecial   #5; //Method "<init>":()V
   7:   putstatic   #6; //Field t:LTest;
   10:  return

public static void main(java.lang.String[])   throws java.lang.Exception;
  Code:
   0:   invokestatic    #7; //Method createInstance:()V
   3:   return

}

我看不到任何与内存屏障相关的内容,然后我将volatile删除并再次反编译,字节码根本没有改变。

我怎样才能在字节码中找到任何东西?

【问题讨论】:

    标签: java jvm jit volatile


    【解决方案1】:

    内存屏障的概念在 Java 规范级别并不存在。它是某些 CPU 架构的低级实现细节,例如当今最流行的 NUMA 架构。

    因此,您需要查看由特定 JVM 实现(例如 x86 架构上的 HotSpot)中的即时编译器生成的机器代码。在那里,如果你足够熟练地解释 x86 机器代码,你就会看到内存屏障的表现。

    【讨论】:

    • 谢谢,@Marko,虽然内存屏障是由 JIT 产生的,但我认为字节码中应该有一些语法来指示变量是易失的,不是吗?字节码和非易失性一样,JVM怎么知道有易失性? :D
    • 它是变量本身的标志,而不是访问它的代码。
    • 有什么反编译工具可以告诉我 volatile 变量的详细信息吗?
    • Javap 默认不显示成员变量。试试javapc -c -private Testjavap -help 获取更多选项)。
    【解决方案2】:

    如果你用 javap 和正确的选项测试它,标志 ACC_VOLATILE 是可见的:

    javap  -v -p Test
    

    打印:

     private static volatile Test t;
     flags: ACC_PRIVATE, ACC_STATIC, ACC_VOLATILE
    

    (标志在 jvm 规范中定义 Chapter 4. The class File Format

    【讨论】:

      【解决方案3】:

      volatile 添加到该字段不会更改读取或写入该字段的Java 字节码。它仅在需要时通过 JVM 或 JIT 编译输出更改程序的解释。它还会影响优化。

      Field flags

      Read and Write synchronization

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-04-14
        • 2016-09-17
        • 1970-01-01
        • 2019-12-10
        • 2011-05-21
        • 2018-12-30
        相关资源
        最近更新 更多