Я разрабатываю интерфейс JNI, который передает строковые параметры из Java в C ++. Мне нужна высокая производительность, и я смог использовать Direct ByteBuffer и String.getBytes () для этого достаточно хорошо, но штраф за передачу строк в C / C ++ все еще остается довольно высоким. Я недавно читал о небезопасном классе Open JDK. Эта отличная страница Я начал, но я считаю, что «Небезопасно» ужасно, но по понятным причинам плохо документировано.
Мне интересно, если я использую класс Unsafe, чтобы получить указатель на строку и передать ее в C ++, есть ли риск того, что объект переместился до того, как был введен код C ++? И даже когда C ++ выполняется? Или эти адреса, предоставленные небезопасным кодом, как-то закреплены? Если они не закреплены, чем полезны эти небезопасные указатели?
Небезопасный не предназначен для взаимодействия с JNI. Таким образом, полученный через Unsafe может измениться в любое время (даже параллельно с вашим C ++).
JNI API имеет возможность закреплять объект в памяти для доступа к содержимому массива (в JVM HotSpot это блокировало бы GC, что может отрицательно влиять на продолжительность паузы GC).
В частности, Get * ArrayElements будет закреплять массив до тех пор, пока вы явно не выполните Release * ArrayElements. GetStringChars работает аналогичным образом.
Прямой ByteBuffer хранит указатель на буфер памяти вне кучи, но этот буфер не перемещается, и вы можете получить к нему доступ для нативного кода.
Я читал Java источник для java.misc.Unsafe и иметь немного больше понимания.
У небезопасных есть как минимум два способа обращения с памятью.
allocateMemory / reallocateMemory / FreeMemory / и т.д. — Насколько я могу судить, это распределение памяти находится за пределами кучи, поэтому не сталкивается с проблемами GC’ing. Я косвенно проверил это, и кажется, что возвращаемое длинное просто указатель на память. Весьма вероятно, что этот тип памяти безопасен для передачи через JNI в нативный код. И Java-код приложения должен иметь возможность быстро изменять / запрашивать его до и после вызовов JNI, используя некоторые другие встроенные небезопасные методы, которые поддерживают этот стиль указателя памяти.
+ смещение объекта — Эти методы принимают указатель на объект и токен смещения, чтобы указать, где в объекте получить / изменить значение. Предположительно, объекты всегда находятся в куче Java, но передача объекта этим методам, вероятно, помогает устранить сложности GC. Звучит так, будто «смещение» иногда является «cookie», а не фактическим смещением, но это также звучит так, как и в случае массивов, arrayBaseOffset () возвращает «смещение», которым можно манипулировать арифметически. Я не знаю, является ли этот объект + смещение безопасным для кода JNI. Я не вижу метода для генерации указателя непосредственно на объект Java в куче, которую можно (опасно) пройти через JNI. Можно передать объект и смещение, но учитывая стоимость передачи Объектов через JNI, этот подход все равно не является привлекательным.
Как (1), код связанный со страницей, на которую я ссылаюсь в своем сообщении, вероятно, довольно безопасен для взаимодействий JNI. При работе со String он использует подход объект + смещение, но использует подход (1) при работе с прямым ByteBuffer, который всегда находится вне кучи Java. Direct ByteBuffer очень дружелюбен к JNI и часто может использоваться таким образом, чтобы избежать затрат на передачу объекта JNI, о которых я упоминаю в своем комментарии к Тому выше.