【混合编程jni 】第八篇之Jni对虚拟机的操作
写了好多了,今天继续写一下对虚拟机的一些操作。
创建虚拟机
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++操作一个工具
首先要获得工具的所有权
然后使用对应的功能
最后扔掉这个工具
虚拟机就是一个可以运行脚本的盒子
- 点赞
- 收藏
- 关注作者
评论(0)