Как декомпилировать изменчивую переменную в Java?

#java #volatile

Вопрос:

Мне сказали, что 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 и декомпилирую его снова, байтовый код вообще не меняется.

Как я мог найти что-нибудь в байтовом коде ?

Ответ №1:

Концепция барьера памяти не существует на уровне спецификации Java. Это низкоуровневая деталь реализации некоторых архитектур процессоров, таких как архитектура NUMA, которая является наиболее популярной сегодня.

Поэтому вам нужно будет взглянуть на машинный код, созданный компилятором точно в срок внутри конкретной реализации JVM, такой как HotSpot на архитектуре x86. Там, если вы достаточно квалифицированы для интерпретации машинного кода x86, вы увидите проявление барьера памяти.

Комментарии:

1. Спасибо, @Marko, Хотя барьер памяти создается JIT, я думаю, что в байтовом коде должен быть какой-то синтаксис, указывающий, что переменная изменчива, не так ли ? Байтовый код точно такой же, как энергонезависимый, как JVM может знать, что есть энергонезависимый ? 😀

2. Это флаг для самой переменной, а не для кода, который обращается к ней.

3. Есть ли какой-нибудь инструмент декомпиляции, который мог бы показать мне детали изменчивой переменной ?

4. Javap по умолчанию не отображает переменные-члены. Попробуйте javapc -c -private Test ( javap -help для получения дополнительных опций).

Ответ №2:

Если вы протестируете его с помощью javap и правильных опций, будет виден флаг ACC_VOLATILE:

 javap  -v -p Test
 

Печать:

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

(флаги определены в главе 4 спецификации jvm. Формат файла класса )

Ответ №3:

Добавление volatile в поле не изменяет байт-код Java, который считывает или записывает поле. Это изменяет интерпретацию программы только с помощью JVM или JIT-компиляции, если это необходимо. Это также влияет на оптимизацию.

Флаги полей

Синхронизация чтения и записи