Изменение указателя класса в заголовке объекта - PullRequest
0 голосов
/ 15 мая 2018

Я попытался изменить указатель класса на объект, чтобы он указывал на другой класс с идентичной настройкой.Чтобы быть точным, для моего теста я использовал копию исходного класса с измененным методом toString(), просто чтобы распечатать что-то еще.

Предполагая, что JVM упорядочивает атрибуты одинаково в объектах памяти двух классов, они должны выглядеть одинаково.

Таким образом, в моем тесте я получил указатель klass из объекта нового класса и установил объект старого, оригинального класса.После вызова toString() я увидел новый вывод, как и ожидалось.

Однако, когда я делал это в цикле, JVM зависала.Я попытался создать new Test() объекты и изменил указатель класса так, чтобы он указывал на Test2 следующим образом (примечание: сжатый 64-битный ООП):

int test2KlassIdentifier = unsafe.getInt(test2Obj, 8L);
unsafe.putInt(testObj, 8L, test2KlassIdentifier);

После создания сотен тысяч объектов я получил дамп ядра:

#  Internal Error (C:\ojdkbuild\lookaside\java-1.8.0-openjdk\hotspot\src\share\vm\opto\memnode.cpp:906), pid=27120, tid=0x0000000000009374
#  assert(!(adr_type->isa_oopptr() && adr_type->offset() == oopDesc::klass_offset_in_bytes())) failed: use LoadKlassNode instead

Затем я уменьшил число, чтобы создать только 100.000 -> без дампа ядра, пока не создал кучу new Object() с.

Так что я чувствую, что это проблема, связанная с ГК, и что мои изменения испортили что-то внутри.Однако я хотел бы понять, чем мой «пропатченный» объект отличается от вновь созданного объекта типа Test2

1 Ответ

0 голосов
/ 15 мая 2018

Не пытайтесь обмануть JVM.Такие эксперименты почти всегда обречены на неудачу.

В этом конкретном случае JIT-компилятор отклоняет 'обычную' операцию загрузки со смещением # 8, поскольку предполагает, что только LoadKlassNode разрешеночитать на klass_offset.Но есть много других причин, по которым такие уловки могут привести к сбою JVM.

Даже если трюк иногда работает в интерпретируемом коде, он может потерпеть неудачу после компиляции JIT, поскольку понятие класса объекта намного больше, чем простоссылка в заголовке объекта.Машинный код, сгенерированный для одного конкретного класса, становится недействительным, если вы попытаетесь вызвать его в другом экземпляре: подумайте об абсолютных адресах в потоке инструкций и т. Д.

Также помните, что классы могут иметь несовместимые состояния при изменении заголовкаНапример, они имеют разные состояния кеша постоянного пула и, возможно, другие структуры, которые JVM заполняет лениво.

...