Каковы последствия, если мы попытаемся постоянно подключать Native Thread к DVM (JVM)?

Можно ли постоянно подключать собственный поток к JVM (AttachCurrentThread) (или), лучше ли прикрепить его когда-либо (вызовы java-функций) и отсоединиться сразу после завершения работы.

Я написал пример родного приложения с вышеуказанными случаями, не нашел разницы. Но при поиске в googling я смутно узнал, что при подключении к JVM планирование потоков JVMs отвечает за планирование, иначе ОС будет планировать собственный поток (если не подключен). Это правда?

Важно отсоединить любой поток, который был ранее прикреплен; в противном случае программа не выйдет, когда вы вызовете DestroyJavaVM. - http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniref.html#attach

Будут ли какие-либо проблемы с производительностью?
Пожалуйста, дайте мне знать, если кто-нибудь знает, это мой важный аспект дизайна.

Спасибо и с уважением.

Ответ 1

Вообще говоря, основная стоимость исполнения - это создание потоков на уровне ОС. Либо поток создается изначально, а затем привязан или непосредственно создан как java.lang.Thread из Java API.

Если вы повторно используете один и тот же собственный поток, производительность будет хорошей. Кстати, не создавайте десятки собственных потоков.

JVM не определяет собственно потоки. Это может заставлять их в состоянии сна по разным причинам, например сбор мусора. В этом конкретном случае он должен дождаться вызова JNI из собственного потока перед сбором. Поэтому вам нужно избегать слишком длительного выполнения кода без вызова JNI, чтобы поддерживать низкое потребление кучи VM.

Кроме того, вы должны позаботиться о вызове DeleteLocalRef перед отсоединением собственного потока, иначе ваша виртуальная машина будет утечка памяти.

Ответ 2

Когда нативный поток подключен постоянно, он не может выйти из собственного потока. Его сбой, когда мы пытаемся выйти из родного потока без отсоединения. Но когда мы отделились, родной поток смог сделать изящный выход.

Ответ 3

У меня не было никаких последствий, кроме повышения производительности.

Это именно то, что я делаю в приложении, которое перемещает непосредственно распределенные данные ByteBuffer между двумя слоями. Я обнаружил, что стоимость постоянного крепления/отсоединения была очень высокой, как и следовало ожидать. Мой подход заключается в запуске одного потока, управляемого Java, который запускает блокирующий JNI-вызов при запуске, который на уровне C/С++ содержит цикл состояния/сигнального стиля (чтобы не дожидаться циклов процессора). Затем я могу передать сигнал в цикл в любое время, когда данные готовы к обработке, и, наоборот, я могу сигнализировать до Java, когда тяжелая работа будет выполнена.

new Thread(() -> myBlockingJNICall()).start();

Затем вниз в слое C:

#ifdef __cplusplus
extern "C"
{
#endif // __cplusplus

    static JavaVM *jvm = nullptr; // captures the JVM on load

    JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *the_jvm, void* /*reserved*/)
    {
        jvm = the_jvm;
        return JNI_VERSION_1_2; // must export 1_2 to use any of the new functions, 1_1 otherwise
    }

    JNIEXPORT jboolean JNICALL Java_myBlockingJNICall(JNIEnv *env, jobject)
    {
       // loop forever waiting for work and using env for signalling
       // jvm is stored in case we need to manually attach (or perform more complex work requiring jvm access)
       return JNI_TRUE;
    }

#ifdef __cplusplus
}
#endif // __cplusplus