JVM, постоянный пул, куча и адреса

Если я создаю новый элемент в сборке Jasmin и затем сохраняю его, я делаю это с инструкцией aload, так как это адрес:

    new Object
    dup
    invokespecial.....
    astore_3 ; load the object reference into local variable 3

Теперь, если я хочу сохранить строку из пула констант... я бы создал ее с помощью ldc, а затем также сохранил с помощью aload:

    ldc "Great string"
    astore_3 ; save the reference to the actual string in the constant pool

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

После проверки байт-кода кажется, что фактический адрес в пуле констант в моем случае - это просто 1-байтовый индекс (я думаю, что основная ссылка на пул констант также где-то хранится)... теперь я знаю, что это ссылка на сом-данные UTF8 в константном пуле, но где находится настоящая строка или это просто ссылка на массив байтов где-то еще? Проверка адреса "нового объекта" в куче, которую я не смог сделать..... в основном, мне нужно выяснить, как эти две области памяти могут использовать одну и ту же форму инструкций и как JVM управляет решить, является ли адрес смещением в пуле констант или объектом в куче?

2 ответа

Решение

Байт-код, интерпретируемый JVM, не обязательно совпадает с байт-кодом, записанным в .class файл. Многие JVM выполняют так называемое переписывание байт - кода на разных этапах выполнения.

Как и HotSpot JVM. Когда класс инициализируется, HotSpot переписывает ldc байт-коды, ссылающиеся на записи String в пуле констант с JVM-специфичной fast_aldc Байт-код, который ссылается на объекты (т.е. java.lang.String экземпляры) в кэш CP. Когда такое fast_aldc Байт-код выполняется впервые, JVM разрешает постоянную запись пула, создает строку в куче Java и заполняет кэш CP ссылкой на эту строку. При дальнейшем выполнении того же байт-кода JVM мгновенно получит ссылку из кэша CP и отправит ее в стек Java.

После интерпретации ldc Байт-код (или его переписанная форма) в верхней части стека будет содержать действительную ссылку на объект в Java Heap. Такой же вид ссылки производится new байткод. Таким образом, нет необходимости различать ссылочные типы.

Вот как работает переводчик. Конечно, после того, как метод JIT-скомпилирован, больше нет байт-кодов, ссылок на постоянный пул и т. Д. Все это просто абстракции. Просто модель.

Во-первых, весь формат байт-кода - это просто абстракция, предоставляемая виртуальной машиной. Это не обязательно имеет какое-либо сходство с фактическим представлением кода или памяти во время выполнения.

Во-вторых, пул констант представляет собой таблицу из 65 535 записей, в которой используются 16-битные индексы. Поскольку индексирование пула констант с помощью небольшого индекса и типа категории 1 является такой распространенной задачей, для него существует специальная стенографическая инструкция - ldc.

Инструкция ldc использует однобайтовый индекс, поэтому она может использоваться только для первых 255 записей. Если вы хотите получить доступ к записям выше этого, вам нужно использовать двухбайтовую форму ldc_w. Ситуация аналогична другим кратким инструкциям, таким как aload_3 vs aload 3 против aload 3.

И снова, это все абстракция. На практике виртуальная машина преобразует пул констант в более дружественный внутренний формат и может компилировать фактические указатели в свое место выполнения в коде. Но это только одна из возможных реализаций.

Другие вопросы по тегам