如果我们尝试将本机线程永久地附加到DVM(JVM)会有什么后果?

时间:2011-12-20 12:24:28

标签: java android multithreading android-ndk java-native-interface

将本机线程永久地附加到JVM(AttachCurrentThread)是否可行(或者)是否需要在需要时(调用java函数)进行附加并在工作完成后立即分离

我用上述案例编写了一个示例本机应用程序,没有发现任何差异。但是通过谷歌搜索,模糊地我才知道,当连接到JVM时,JVM的线程调度负责调度,否则OS将调度本机线程(如果没有附加)。这是真的吗?

分离先前已连接的任何线程非常重要;否则,当您调用DestroyJavaVM时,程序不会退出。 - http://java.sun.com/developer/onlineTraining/Programming/JDCBook/jniref.html#attach

是否有任何性能问题?
如果有人知道,请告诉我,这是我的重要设计方面。

谢谢&问候。

3 个答案:

答案 0 :(得分:4)

一般来说,主要的性能成本是OS级别的线程创建。该线程是本机创建的,然后从Java API附加或直接创建为java.lang.Thread

如果您重复使用相同的本机线程,性能将会很好。顺便说一句,不要创建数十个本机线程。

JVM does not schedule threads itself。由于垃圾收集等各种原因,它可能会迫使他们处于睡眠状态。在这种特定情况下,它必须在收集之前等待来自本机线程的JNI调用。因此,您必须避免在没有JNI调用的情况下执行过长的代码,以保持较低的VM堆耗。

此外,在分离本机线程之前,您必须注意调用DeleteLocalRef,否则您的VM将泄漏内存。

答案 1 :(得分:1)

永久附加本机线程时,无法退出本机线程。当我们尝试退出本机线程而不分离时崩溃。但是当我们分离时,原生线程能够优雅地退出。

答案 2 :(得分:0)

除了提升表现外,我没有遇到任何后果。

这正是我在一个应用程序中所做的事情,该应用程序在两个层之间重新分配直接分配的ByteBuffer数据。我发现不断附加/分离的成本非常高,正如人们所预料的那样。我的方法是启动一个Java管理的线程,该线程在启动时进行阻塞JNI调用,在C / C ++层中包含条件/信号样式循环(以便不吃掉CPU周期)。然后,只要数据准备好进行处理,我就可以向环路发出信号,相反,当完成这项工作时,我可以向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