【混合编程jni 】第八篇之Jni对虚拟机的操作

举报
香菜聊游戏 发表于 2022/06/26 21:31:07 2022/06/26
【摘要】 写了好多了,今天继续写一下对虚拟机的一些操作。创建虚拟机jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args);加载并初始化一个 Java VM,并返回一个指向 JNI 接口指针的指针。调用的线程JNI_CreateJavaVM()被认为是 主线程。不支持在单个进程中创建多个 VM。JavaVMInitArgs vm...

写了好多了,今天继续写一下对虚拟机的一些操作。

创建虚拟机

jint JNI_CreateJavaVM(JavaVM **p_vm, void **p_env, void *vm_args);

加载并初始化一个 Java VM,并返回一个指向 JNI 接口指针的指针。调用的线程JNI_CreateJavaVM()被认为是 主线程。

不支持在单个进程中创建多个 VM。

JavaVMInitArgs vm_args;
JavaVMOption options[4];
 
options[0].optionString = "-Djava.compiler=NONE";           /* disable JIT */
options[1].optionString = "-Djava.class.path=c:\myclasses"; /* user classes */
options[2].optionString = "-Djava.library.path=c:\mylibs";  /* set native library path */
options[3].optionString = "-verbose:jni";                   /* print JNI-related messages */
 
vm_args.version = JNI_VERSION_1_2;
vm_args.options = options;
vm_args.nOptions = 4;
vm_args.ignoreUnrecognized = TRUE;
 
/* Note that in the JDK/JRE, there is no longer any need to call
 * JNI_GetDefaultJavaVMInitArgs.
 */
res = JNI_CreateJavaVM(&vm, (void **)&env, &vm_args);
if (res < 0) ...

附加到虚拟机

AttachCurrentThread()

因为JNI 接口指针 ( JNIEnv) 仅在当前线程中有效。如果另一个线程需要访问 Java VM,

它必须首先调用 AttachCurrentThread()以将自己附加到 VM 并获取 JNI 接口指针。

一旦连接到 VM,本机线程就像在本机方法中运行的普通 Java 线程一样工作。

从 VM 分离

jint DetachCurrentThread(JavaVM *vm);

附加到 VM 的本机线程必须调用 DetachCurrentThread()以在退出之前分离自身。如果调用堆栈上有 Java 方法,则线程不能自行分离。

卸载虚拟机

JNI_DestroyJavaVM()

VM 会一直等待,直到 当前线程是唯一的非守护程序用户线程,然后才会实际卸载。

用户线程包括 Java 线程和附加的本机线程。存在此限制是因为 Java 线程或附加的本机线程可能持有系统资源,例如锁、窗口等。VM无法自动释放这些资源

通过在卸载 VM 时将当前线程限制为唯一运行的线程,释放任意线程持有的系统资源的负担就落在了程序员身上

看个例子

static void vad_status_callback(int64_t userData, int state, int offset)
{
    JNIEnv *newEnv;
    JavaVMAttachArgs args;
    args.version = JNI_VERSION_1_6;
    vad_context_t *vad_context_ptr = instance_map[userData];
    if (!vad_context_ptr)
    {
        cout << "vad_status_callback. cannot find instance context. id:" << userData << " total size:" << instance_map.size() << endl;
        return;
    }
    //	回调没有jniEnv指针,需要获取线程指针
    if (jvm->AttachCurrentThread((void **)&newEnv, &args) != 0) 
    {
        return;
    }
    jclass g_clazz = newEnv->GetObjectClass(vad_context_ptr->java_instance);
    jmethodID on_state_changed_method = newEnv->GetMethodID(g_clazz, "onStateChanged", "(II)V");
    newEnv->CallVoidMethod(vad_context_ptr->java_instance, on_state_changed_method, (jint)state, (jint)offset);
    if (newEnv->ExceptionCheck())
    {
        newEnv->ExceptionClear();
    }
    //	脱离线程
    jvm->DetachCurrentThread();
}

总结

对虚拟机的操作可以理解为C++操作一个工具

首先要获得工具的所有权

然后使用对应的功能

最后扔掉这个工具

虚拟机就是一个可以运行脚本的盒子



【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。