JavaVM、JNIEnv和jobject的理解

  1. 三者特点:

1)JavaVM:能够跨越线程,能够跨越函数;

2)JNIEnv:不能跨越线程,否则奔溃,可以跨越函数;

3)jobject:不能跨越线程,否则奔溃,不能跨越函数,否则奔溃。

  1. 代码验证

1)java层native函数定义、在主线程和子线程调用验证

/*** java层主线程调用*/
public native void nativeFun0();
public native void nativeFun1();
/*** java层子线程调用*/
public native void nativeFun2();/*** 按钮点击事件*/
public void clickMethod0(View view) {nativeFun0();
}public void clickMethod(View view) {nativeFun1();
}public void clickMethod2(View view) {new Thread() {@Overridepublic void run() {super.run();nativeFun2(); // Java的子线程调用}}.start();
}

2)native层函数实现和native层函数子线程实现

// 定义全局javaVM,用于多线程使用
JavaVM *java_vm = nullptr;// 重写JNI_OnLoad函数,在执行System.loadLibrary时,调用该函数,在此进行动态注册
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *javaVm, void *) {::java_vm = javaVm;return JNI_VERSION_1_6;
}/*** 在Java层主线程调用nativeFun0*/
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_thread_MainActivity_nativeFun0(JNIEnv *env, jobject thiz) {JavaVM *javaVm = nullptr;env->GetJavaVM(&javaVm);// 打印:当前函数env地址, 当前函数jvm地址, 当前函数job地址,  JNI_OnLoad的jvm地址LOGE("Java层主线程 nativeFun0 当前函数env地址%p,  当前函数jvm地址:%p,  当前函数job地址:%p, JNI_OnLoad的jvm地址:%p\n",env, javaVm, thiz, ::java_vm);
}/*** 定义子线程的函数指针*/
void *run(void *) {JNIEnv *jniEnv = nullptr;// 在子线程附件一个jniEnv::java_vm->AttachCurrentThread(&jniEnv, nullptr);LOGE("native层子线程 run jvm地址:%p,  当前run函数的newEnv地址:%p \n", ::java_vm, jniEnv);// 释放::java_vm->DetachCurrentThread();return nullptr;
}/*** 在Java层主线程调用nativeFun1,native层调用子线程的函数指针*/
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_thread_MainActivity_nativeFun1(JNIEnv *env, jobject thiz) {JavaVM *javaVm = nullptr;env->GetJavaVM(&javaVm);// 打印:当前函数env地址, 当前函数jvm地址, 当前函数clazz地址,  JNI_OnLoad的jvm地址LOGE("Java层主线程 nativeFun1 当前函数env地址%p,  当前函数jvm地址:%p,  当前函数clazz地址:%p, JNI_OnLoad的jvm地址:%p\n",env,javaVm, thiz, ::java_vm);// 创建子线程pthread_t pid;pthread_create(&pid, nullptr, run, nullptr);
}/*** 在Java层子线程调用nativeFun2*/
extern "C"
JNIEXPORT void JNICALL
Java_com_ndk_thread_MainActivity_nativeFun2(JNIEnv *env, jobject thiz) {JavaVM *javaVm = nullptr;env->GetJavaVM(&javaVm);// 打印:当前函数env地址, 当前函数jvm地址, 当前函数clazz地址,  JNI_OnLoad的jvm地址LOGE("Java层子线程 nativeFun2 当前函数env地址%p,  当前函数jvm地址:%p,  当前函数clazz地址:%p, JNI_OnLoad的jvm地址:%p\n",env,javaVm, thiz, ::java_vm);
}
  1. 小结

查看打印log分析

1)所有的JavaVM地址都是相同的,即JavaVM为同一个;

2)主线程的JNIEnv地址是相同,子线程的JNIEnv地址是不相同;

3)主线程的jobject地址是相同,子线程的jobject地址跟主线程是不相同;

结论:

1. JavaVM全局,绑定当前进程, 只有一个地址

2. JNIEnv线程绑定, 绑定主线程,主线程相同,故主线程地址相同;绑定子线程,多个子线程,故子线程地址不相同。

3. jobject 谁调用JNI函数,谁的实例会给jobject,如:MainActivity主线程调用地址指向MainActivity;子线程Thread程调用地址指向子线程Thread。

JNIEnv和jobject的崩溃解决:

JNIEnv:

使用全局的JavaVM附加当前异步线程 得到权限env操作。

JNIEnv *jniEnv = nullptr;
// 在子线程附件一个jniEnv
::java_vm->AttachCurrentThread(&jniEnv, nullptr);
// 释放
::java_vm->DetachCurrentThread();

jobject:

默认是局部引用,提升全局引用,可解决此问题。

env->NewGlobalRef(jobject); // 提升全局引用

NDK JNI JavaVM、JNIEnv和jobject的理解相关推荐

  1. C语言调用jni中JNIEnv指针使用和理解

    使用C语言调用jni的时候,需要和java的环境对象和虚拟机对象交互.它们的C语言定义如下. typedef const struct JNINativeInterface* JNIEnv; type ...

  2. 【Android FFMPEG 开发】C++ 回调 Java 方法 模板 ( JavaVM *vm | JNIEnv *env | jobject instance | 引用类型 | 模板代码示例 )

    文章目录 I . Native 调用 Java 方法 II . JNIEnv *env 与 jobject instance III . JavaVM *vm IV . 局部引用 与 全局引用 分析 ...

  3. android jni 中jnienv,android JNI中JNIEnv類型和jobject類型的解釋

    JNIEXPORT void JNICALL Java_com_jni_demo_JNIDemo_sayHello (JNIEnv *env, jobject obj) { cout< } 對於 ...

  4. JNI学习笔记:JNIEnv、jobject与jclass详解

    1 前言 2 JNIEnv指针 3 jobject与jclass类型 1 前言 在进行JNI编程开发的时候,使用javah生成Native方法对应的Native函数声明,会发现所有的Native函数的 ...

  5. 【Android 系统开发】Android JNI 之 JNIEnv 解析

    . jni.h文件 : 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一个文件, 位置是 $/android-ndk-r9d/platforms/android ...

  6. JNI详解---从不懂到理解

     Chap1:JNI完全手册... 3 Chap2:JNI-百度百科... 11 Chap 3:javah命令帮助信息... 16 Chap 4:用javah产生一个.h文件... 17 Chap ...

  7. Android JNI 之 JNIEnv 解析

    jni.h文件 : 了解 JNI 需要配合 jni.h 文件, jni.h 是 Google NDK 中的一个文件, 位置是$/android-ndk-r9d/platforms/android-19 ...

  8. NDK JNI Android Studio开发与调试DEMO(三)(生成 .so 文件)

    Android Studio NDK 开发与调试(生成 .so 文件) 温馨提示:如果你的 Android Studio 版本在 3.0以上 , 建议你用 cMake /ndk-build 的新姿势进 ...

  9. NDK JNI方式读写Android系统的demo(二)

    NDK & JNI(方式读写Android系统的Demo) 大家都知道Android系统是一种基于Linux的自由及开放源码的操作系统,所以读写GPIO也可以直接用Linux那一套export ...

最新文章

  1. 任正非最新署名文章:不要因为美国打压而放弃全球化战略
  2. IOS中UITableView异步加载图片的实现
  3. boost::describe模块实现连载功能的测试程序
  4. Netty HTTP on Android
  5. halcon中面到面的距离_halcon学习笔记——(8)由标定板得到测量平面位姿-阿里云开发者社区...
  6. 9.广义霍夫变换——广义霍夫变换算法和识别中的应用、现在的霍夫算法及识别中的应用_2
  7. 【转】Unity利用WWW http传输Json数据
  8. android studio 上手使用 大水逼问题
  9. 机器学习- 吴恩达Andrew Ng Week4 神经网络Neural Networks知识总结
  10. 推荐一个js脚本的字体拟合模型
  11. 排名前三的网址导航站和源码资源站分享
  12. 9.郝斌C语言笔记——变量的作用域和存储方式
  13. 利用opencv 做一个疲劳检测系统(2)
  14. vscode英文感叹号没出现提示文本解决方法
  15. 设置oracle sys密码修改,Oracle修改SYS密码
  16. matlab has encountered,matlab运行程序时出现“matlab has encountered an internal problem
  17. PS四种扁平化设计风格-网摘
  18. Linux /centos7源码编译安装Nginx
  19. git did not exit cleanly (exit code 128)我个人解决方案
  20. Discuz招商加盟门户网站整站模板/加盟项目网站商业版源码/整站带测试数据

热门文章

  1. 二维码跳转不同的 app store
  2. 天刀各大服务器位置,天涯明月刀手游可以查看到好友所在区吗 好友服务器位置查看方法[多图]...
  3. 红旗Linux刻录到U盘,安装红旗Asianux_openEuler 8.1(欧拉版)的方法
  4. access中所有女生的记录,ACCESS建查询,如何查两个表里的内容
  5. 会员积分储值充值管理系统asp源码基于微信公众号
  6. 继承和实现区别java_java中继承和实现有什么区别,分别给程序带来了怎样的好处?...
  7. Deprecated API
  8. 《数字图像处理》题库5:计算题 ③
  9. 牛刀:2010年上海房价第一个开始下跌
  10. csv文件用Excel打开乱码如何处理