Выравнивание выделения памяти Java - PullRequest
15 голосов
/ 11 марта 2011

Я знаю, что это странный вопрос на Java, но есть ли способ позволить динамическому распределению памяти Java быть выровненным с некоторыми ограничениями выравнивания? Например, возможно ли динамическое размещение объектов, которые выровнены по размеру страницы?

Причина, по которой я хочу это сделать, заключается в том, что я собираюсь получить доступ к объекту Java из нативного кода через интерфейс JNI, а библиотека нативного кода требует, чтобы объект был выровнен.

Спасибо.

Ответы [ 3 ]

7 голосов
/ 11 марта 2011

Нет, это невозможно. Имейте в виду, что объекты в куче в Java могут перемещаться во время сборки мусора. У вас есть несколько вариантов:

  1. Прекратить доступ к объектам Java напрямую из JNI. Скопируйте то, что вас волнует, в предоставленный JNI буфер, который уже выровнял собственный код.
  2. Использовать ByteBuffer.allocateDirect () . Затем найдите область вашего буфера, которая правильно выровнена. Одним из способов сделать это является выделение буфера при запуске и повторная попытка операции, чувствительной к выравниванию, с различными смещениями, пока она не заработает. Это хак!
5 голосов
/ 08 января 2013

См. Это сообщение в блоге для более широкого обсуждения прямого выравнивания памяти в Java, которое также покрывает ваши требования. Подведем итог:

  1. До JDK 1.6 все прямые байтовые буферы выровнены по страницам, поэтому, если вы используете версию Java, вы отсортированы.
  2. Начиная с версии 1.7, следуйте методу, описанному в сообщении, чтобы получить выровненный буфер.

Я бы порекомендовал вам не делать повторные распределения, пока вы не нажмете правильный адрес. Это было бы очень плохо для вашего программного обеспечения. Если вы планируете повторно захватывать адрес, я бы порекомендовал вам его кэшировать, если вы планируете использовать метод отражения, описанный выше. В качестве альтернативы используйте метод, описанный в посте, используя Unsafe, чтобы получить значение поля адреса.

2 голосов
/ 11 марта 2011

Прекрасных вариантов не существует, так что вот такие уродливые:

Если вы используете Sun (сейчас Oracle) JRE 5.0 или 6.0, вы можете использовать следующее:

   ByteBuffer buffer = ByteBuffer.allocateDirect(pageSize);
   Method getAddress = buffer.getClass().getMethod("address");
   long address = getAddress.invoke(buffer);
   // and now send address to JNI

Для доступа к данным в Java используйте buffer . Чтобы получить доступ в JNI, приведите address к указателю. Оба будут видеть / изменять одни и те же данные.

Адрес должен быть выровнен по страницам, но чтобы быть уверенным в этом, вы можете выделить две страницы (наверняка будет достаточно места для полностью выровненной страницы). Затем вы выравниваете адрес на странице и применяете смещение для доступа ByteBuffer.

Еще одна опция для выделения буфера и собственных вызовов, которая работает на любой виртуальной машине, использует класс памяти JNA: http://jna.java.net/javadoc/com/sun/jna/Memory.html. Не пугайтесь с пакетом com.sun . Это с открытым исходным кодом и LGPL.

...