首页 > 其他分享 >JNI中AttachCurrentThread和DetachCurrentThread的问题

JNI中AttachCurrentThread和DetachCurrentThread的问题

时间:2022-11-21 10:23:31浏览次数:66  
标签:调用 DetachCurrentThread 线程 DEBUG AttachCurrentThread JNI JNIEnv

在《Java与CC++交互JNI编程》中有讲过AttachCurrentThreadDetachCurrentThread的使用。

我们知道在jni中我们可以使用pthread或者std::thread创建线程。因为线程并不是从Java环境创建的,所以这时候创建出的线程是没有JNIEnv的。如果需要使用JNIEnv,可以调用JavaVMAttachCurrentThread将当前线程附加到虚拟机。

jint AttachCurrentThread(JNIEnv** p_env, void* thr_args);

AttachCurrentThread可以调用多次,第一次会附加当前线程到虚拟机并返回JNIEnv,之后再调用的时候因为当前线程已经被附加到虚拟机上了,所以就不需要重复附加了,仅仅只返回JNIEnv即可,作用相当于GetEnv

需要注意的是,在线程退出之前我们必须要调用DetachCurrentThread从虚拟机分离当前线程,,不然会造成内存泄露,线程也不会退出。对于native层创建出来的线程,在调用AttachCurrentThread的时候会创建本地引用表,在调用DetachCurrentThread的时候会释放本地引用表。

但是一般我们并不会频繁的调用AttachCurrentThread/DetachCurrentThread,这样效率很低。一般我们在线程的入口函数调用一次AttachCurrentThread,在线程入口函数退出之前调用一次DetachCurrentThread即可。所以一定要手动释放每个本地引用。不然本地引用越来越多,很容易超出最大限制。
下面这个例子很好的演示了AttachCurrentThread/DetachCurrentThread的用法:

#include <jni.h>
#include <pthread.h>
#include <android/log.h>

extern JavaVM *g_vm;
JNIEnv* getEnv();

void* __start_routine(void*) {
    JNIEnv *env1, *env2, *env3, *env4, *env5;
    int ret;

    JavaVMAttachArgs args;
    args.version = JNI_VERSION_1_4;
    args.name = "pthread-test";//给线程起个名字吧,这样在调试或者崩溃的时候能显示出名字,而不是thead-1,thread-2这样的名字。
    args.group = NULL;//java.lang.ThreadGroup的全局引用,作用你懂的。

    //在调用AttachCurrentThread以前,是没有java环境的,所以GetEnv返回的JNIEnv是NULL
    g_vm->GetEnv((void**)&env1,JNI_VERSION_1_4);
    __android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "before AttachCurrentThread env is:%p", env1);

    //调用AttachCurrentThread,将当前线程附加到虚拟机,附加成功后,将会返回JNIEnv
    ret = g_vm->AttachCurrentThread(&env2, &args);
    __android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "do     AttachCurrentThread env is:%p, ret=%d", env2, ret);


    //在调用AttachCurrentThread以后,GetEnv返回了正确的JNIEnv
    g_vm->GetEnv((void**)&env3,JNI_VERSION_1_4);
    __android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "after  AttachCurrentThread env is:%p", env3);

    //再次调用AttachCurrentThread,直接返回JNIEnv,作用相当于GetEnv
    ret = g_vm->AttachCurrentThread(&env4, NULL);
    __android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "retry  AttachCurrentThread env is:%p, ret=%d", env4, ret);

    //从虚拟机分离线程
    g_vm->DetachCurrentThread();

    //在调用DetachCurrentThread以后,GetEnv返回NULL
    g_vm->GetEnv((void**)&env5,JNI_VERSION_1_4);
    __android_log_print(ANDROID_LOG_DEBUG, "MD_DEBUG", "after  DetachCurrentThread env is:%p", env5);
    return NULL;
}

extern "C" JNIEXPORT void Java_com_example_threadtest_PThread_start(JNIEnv *env, jclass clazz) {
    pthread_t thread;
    pthread_create(&thread, NULL, __start_routine, NULL);
}

深入浅出Android NDK之在jni中使用线程
关于JNI开发的一些建议

标签:调用,DetachCurrentThread,线程,DEBUG,AttachCurrentThread,JNI,JNIEnv
From: https://www.cnblogs.com/zuojie/p/16901772.html

相关文章

  • 学习笔记-JNI框架层的Hook利用
    系统框架nativehookJNI函数符号hookJNI函数参数、返回值打印和替换动态注册JNI_OnloadhookRegisterNativesjnitrace引入一个例子,hookGetStringUTFChars这个jn......
  • .preinit_array,.init_array,.init和JNI_OnLoad
    https://www.cnblogs.com/revercc/p/16299712.html在linker初始化的时候linker_main函数在加载了所有ELF文件依赖的so库后,会先调用call_pre_init_constructors()和call_cons......
  • Android JNI 中的线程操作
    公众号回复:OpenGL,领取学习资源大礼包学习一下如何在Native代码中使用线程。Native中支持的线程标准是POSIX线程,它定义了一套创建和操作线程的API。我们可以在Native......
  • 安卓逆向 JNI实先java与C互通
    先来一张吊图jdk_1.6.0_43/include/jni.h 这个头文件的地址头文件分布  我们需要熟悉的 反射获取java中的类1.jclass/类型(JNICALL*FindClass)函数......
  • NDK与JNI开发(1)ndk_build方式开发
    一:概述Android的开发主要是基于java语言进行开发的,所以导致了用AndroidSDK进行开发的工程师们都必须使用Java语言。但是Android平台从一开就已经支持了C/C++了,Google从一......
  • Frida spawn process failed on Android 'Error: VM::AttachCurrentThread failed:
    https://stackoverflow.com/questions/36680128/frida-spawn-process-failed-on-android竟然国内搜不到这个问题。原因是没有将设备resume。办法为device.resume(pid......
  • Java调用C++动态链接库——Jni
    最近项目需要,将C++的算法工程编译成动态链接库,交给Java后台当作函数库调用。就去了解了下Jni。使用起来还是比较方便的。1.  首先编写Java的调用类。例如:  public......