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

Можно ли использовать sun.misc.Unsafe для вызова функций C без JNI?

Часть кода C/С++ может предоставить JNI-метод с массивом указателей на функции. Но есть ли способ вызвать в стек функции, которые указывают указатели массива, непосредственно изнутри кода Java (без использования JNI или аналогичного)? JNI как-то делает что-то подобное, поэтому должен быть способ. Как JNI это делает? Это через sun.misc.Unsafe? Даже если это не так, можем ли мы использовать некоторое небезопасное обходное решение, чтобы получить доступ к JVM-коду, который делает это?

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

4b9b3361

Ответ 1

Является ли JNI медленным?

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

Эти служебные данные могут быть значительными, если нативная функция проста и часто называется. JDK имеет частный API под названием Critical Natives, чтобы уменьшить накладные расходы на функции вызова, которые не требуют значительной части возможностей JNI.

Критические туземцы

Нативный метод должен удовлетворять следующим условиям, чтобы стать критическим нативным:

  • должен быть статическим и не синхронизирован;
  • типы аргументов должны быть примитивными или примитивными массивами;
  • реализация не должна вызывать функции JNI, т.е. не может выделять объекты Java или исключать исключения;
  • не следует запускать в течение длительного времени, так как будет блокировать GC во время работы.

Объявление критического нативного выглядит как обычный JNI-метод, за исключением того, что

  • начинается с JavaCritical_ вместо Java_;
  • у него нет дополнительных аргументов JNIEnv* и jclass;
  • Массивы Java передаются по двум аргументам: первая - длина массива, а вторая - указатель на необработанные данные массива. То есть не нужно вызывать GetArrayElements и друзей, вы можете сразу использовать указатель прямого массива.

например. метод JNI

JNIEXPORT jint JNICALL
Java_com_package_MyClass_nativeMethod(JNIEnv* env, jclass klass, jbyteArray array) {
    jboolean isCopy;
    jint length = (*env)->GetArrayLength(env, array);
    jbyte* buf = (*env)->GetByteArrayElements(env, array, &isCopy);
    jint result = process(buf, length);
    (*env)->ReleaseByteArrayElements(env, array, buf, JNI_ABORT);
    return result;    
}

превратится в

JNIEXPORT jint JNICALL
JavaCritical_com_package_MyClass_nativeMethod(jint length, jbyte* buf) {
    return process(buf, length);
}

Критические туземцы поддерживаются только в JSM HotSpot, начиная с JDK 7. Кроме того, "критическая" версия вызывается только из скомпилированного кода. Поэтому для обеспечения правильной работы вам нужна как критическая, так и стандартная реализация.

Эта функция была разработана для внутреннего использования в JDK. Нет никакой публичной спецификации или чего-то еще. Вероятно, единственная документация, которую вы можете найти, находится в комментариях к JDK-7013347.

Benchmark

Этот тест показывает, что критические уроженцы могут быть в несколько раз быстрее обычных JNI-методов, когда нагрузка на рабочую область очень мала. Чем дольше метод, тем меньше относительные служебные данные.

Производительность вызовов JNI


P.S. В JDK продолжается работа по реализации Native MethodHandles, которая будет служить более быстрой альтернативой JNI. Однако вряд ли он появится до JDK 10.