Подтвердить что ты не робот

Выравнивание распределения памяти Java

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

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

Спасибо.

4b9b3361

Ответ 1

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

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

Ответ 2

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

  • До JDK 1.6 все буферы с прямым байтом выравниваются по страницам, поэтому, если версия java, на которой вы находитесь, сортируется.
  • От 1.7 вы сами по себе, следуйте методу, указанному в сообщении, чтобы получить выравниваемый буфер.

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

Ответ 3

Нет никаких прекрасных вариантов, так что здесь идут уродливые:

Если вы используете 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, используйте буфер. Чтобы получить доступ в JNI, введите адрес в указатель. Оба будут видеть/изменять одни и те же данные.

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

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