JNI学习笔记:JNI原理

一、JNI数据类型

在上节中出现了jstring类型,这里说明一下,JNI有自己的原始数据类型和数据引用类型。

JNI学习笔记:JNI原理_第1张图片

 

二、JNI原理

Java语言的执行环境是Java虚拟机(JVM),JVM其实是主机环境中的一个进程,每个JVM虚拟机都在本地环境中有一个JavaVM结构体,该结构体在创建Java虚拟机时被返回,在JNI环境中创建JVM的函数为JNI_CreateJavaVM。

JNI_CreateJavaVM(JavaVM **pvm, void **penv, void*args);

1、JavaVM

JNI学习笔记:JNI原理_第2张图片

其中JavaVM是Java虚拟机在JNI层的代表,JNI全局仅仅有一个JavaVM结构中封装了一些函数指针(或叫函数表结构),JavaVM中封装的这些函数指针主要是对JVM操作接口。另外,在C和C++中的JavaVM的定义有所不同,在C中JavaVM是JNIInvokeInterface_类型指针,而在C++中有对JNIInvokeInterface_进行了一次封装,比C中少了一个参数,这也是为什么JNI代码更推荐使用C++来编写的原因。

2、JNIEnv

JNIEnv是当前Java线程的执行环境,一个JVM对应一个JavaVM结构,而一个JVM中可能创建多个Java线程,每个线程对应一个JNIEnv结构,它们保存在线程本地存储TLS中。JNIEnv是一个线程相关的结构体,该结构体代表了Java在本线程的执行环境。

因此,不同的线程的JNIEnv是不同,也不能相互共享使用。JNIEnv结构也是一个函数表,在本地代码中通过JNIEnv的函数表来操作Java数据或者调用Java方法。也就是说,只要在本地代码中拿到了JNIEnv结构,就可以在本地代码中调用Java代码。

JNIEnv的作用:

  • 调用Java 函数:JNIEnv代表了Java执行环境,能够使用JNIEnv调用Java中的代码
  • 操作Java代码:Java对象传入JNI层就是jobject对象,需要使用JNIEnv来操作这个Java对象

JNIEnv的创建:

  • C 中——JNIInvokeInterface:JNIInvokeInterface是C语言环境中的JavaVM结构体,调用 (AttachCurrentThread)(JavaVM, JNIEnv*, void) 方法,能够获得JNIEnv结构体
  • C++中 ——_JavaVM:_JavaVM是C++中JavaVM结构体,调用jint AttachCurrentThread(JNIEnv** p_env, void* thr_args) 方法,能够获取JNIEnv结构体;

JNIEnv的释放:

  • C 中释放:调用JavaVM结构体JNIInvokeInterface中的(DetachCurrentThread)(JavaVM)方法,能够释放本线程的JNIEnv
  • C++ 中释放:调用JavaVM结构体_JavaVM中的jint DetachCurrentThread(){ return functions->DetachCurrentThread(this); } 方法,就可以释放 本线程的JNIEnv

JNIEnv结构:

JNIEnv是一个指针,指向一个线程相关的结构,线程相关结构指向JNI函数指针数组,这个数组中存放了大量的JNI函数指针,这些指针指向了详细的JNI函数。

JNI学习笔记:JNI原理_第3张图片

3、JNI引用

在JNI中,定义了三种引用类型:

  • 局部引用(Local Reference)
  • 全局引用(Global Reference)
  • 弱全局引用(Weak Global Reference)

1)局部引用(Local Reference)

最常见的引用类型,基本上通过JNI返回来的引用都是局部引用,例如使用NewObject,就会返回创建出来的实例的局部引用,局部引用值在该native函数有效,所有在该函数中产生的局部引用,都会在函数返回的时候自动释放(freed),也可以使用DeleteLocalRef函数手动释放该应用。之所以使用DeleteLocalRef函数:实际上局部引用存在,就会防止其指向对象被垃圾回收期回收,尤其是当一个局部变量引用指向一个很庞大的对象,或是在一个循环中生成一个局部引用,最好的做法就是在使用完该对象后,或在该循环尾部把这个引用是释放掉,以确保在垃圾回收器被触发的时候被回收。在局部引用的有效期中,可以传递到别的本地函数中,要强调的是它的有效期仍然只是在第一次的Java本地函数调用中,所以千万不能用C++全部变量保存它或是把它定义为C++静态局部变量。

2)全局引用(Global Reference)

全局引用可以跨方法、跨线程使用,直到被开发者显式释放。类似局部引用,一个全局引用在被释放前保证引用对象不被GC回收。和局部应用不同的是,没有俺么多函数能够创建全局引用。能创建全部引用的函数只有NewGlobalRef,而释放它需要使用ReleaseGlobalRef函数

3)弱全局引用(Weak Global Reference)

JDK 1.2 新增加的功能,与全局引用类似,创建跟删除都需要由编程人员来进行,这种引用与全局引用一样可以在多个本地带阿妈有效,不一样的是,弱引用将不会阻止垃圾回收期回收这个引用所指向的对象,所以在使用时需要多加小心,它所引用的对象可能是不存在的或者已经被回收。

 

转自:Android JNI(一)——NDK与JNI基础

你可能感兴趣的:(Android,JNI)