JNI 引用与缓存

转载 2012年03月26日 22:47:08
全局引用/局部引用/弱全局引用
从java虚拟机创建的对象传到本地c/c++代码是会产生引用。根据java垃圾回收机制,只要有引用存在就不会触发引用指向的java对象的垃圾回收。
这些引用在JNI中分三种:
1、全局引用(Global Reference)
2、局部引用(Local Reference)
3、弱全局引用(Weak Global Reference)
---------------------------------------
1、局部引用(常用)基本上通过JNI返回来的引用都是局部引用。
例如:NewObject就会返回创建出来的实例的局部引用。局部应用只在该native函数中有效。所有在该函数中产生的局部引用,都会在函数返回的时候自动释放(freed),也可以使用DeleteLocalRef函数自动释放该引用
在局部引用的有效期中,可以传递到别的函数中,要强调的是他的有效期仍然只在一次的java本地函数调用中,所以千万不能用C++全局变量保存他或是把它定义为C++静态局部变量
2、全局引用
全局引用可以跨越当前线程,在多个native函数中有效,不过需要编程人员手动来释放该引用,全局引用存在期间会防止在java的垃圾回收的回收。
与局部引用不同,全局引用的创建不由JNI自动创建的,全局引用是需要调用NewGlobealRef函数,而释放他需要使用ReleaseGlobalRef函数。
3、弱全局引用
java1.2出来的功能,与全局引用相似,创建、删除都需要由编程人员来进行,这种引用全局引用一样,可以在多个本地代码有效,也跨越多线程有效,不过,这种引用将不会阻止垃圾回收器回收这个引用所指向的对象。
使用NewWeakGlobalRef跟ReleaseWeakGlobalRef来产生和解除引用。
关于引用的一些函数:
jobject NewGlobalRef(jobject obj);//创建全局引用
jobject NewLocalRef(jobject obj);//创建局部引用
jobject NewWeakGlobalRef(jobject obj);//创建弱全局引用
void DeleteGlobalRef(jobject obj);//删除全局引用
void DeleteLocalRef(jobject obj);//删除局部引用
void DeleteWeakGlobalRef(jobject obj);//删除弱全局引用
jboolean IsSameObject(jobject obj1,jobject obj2);//判断两个引用是否指向同一个java对象
这个函数对于弱全局引用有一个特别的功能,把Null传入要比较的对象中,就能够判断弱全局引用所指向的java对象是否被回收
----------------------------------------------------------------------
缓存:
缓存jfieldID/jmethodID
取得jfieldID跟jmethodID的时候会通过该属性/方法名加上签名来查询相应的jfieldID/jmethodID,这种查询相对开销较大,我们可以将这些FieldID/MethodID缓存起来,这样只需要查询一次,以后就使用缓存起来的FieldID/MethodID了
缓存的方式:
1、在使用的时候缓存(Caching at the Point of Use)
2、在Java类初始化时缓存(Caching at the Defining Class's Inititalizer)
----------------
在第一次使用的时候缓存:
在native code中使用static局部变量来保存已经查询过的ID,这样就不会在每次的函数调用时查询,而只要第一次查询成功后就保存起来了。
例子:JNIEXPORT void JNICALL Java_test_native(JNIEnv* env,jobject obj)
     {
        static jfieldID fieldID_string =NULL;
 jclass clazz=env->GetObjectClass(obj);
        if(fieldID_string==NULL)
 {
    fieldID_string=env->GetFieldID(class,"string","Ljava/lang/String;");
 }
 .......................
     }
---------------
在java类初始化的时候缓存
更好的方式就是在任何native函数调用前把id全部存起来。我们可以让java在第一次加载这类的时候首先调用本地代码初始化所有的jfieldID/jmethodID,这样的话就可以省去多次的确定id是否存在的语句,当然,这些jfieldID/jmethodID是定义在c/c++的全局。
使用这种方式还有好处,当java类卸载或是重新加载的手也会重新呼叫该本地代码来重新计算IDs。
例子:java类中:
public class TestNative
{
   static{ initNativeIDs();}
   static native void initNativeIDs();
   int propInt=0;
   String propStr="";
   public native void otherNative();
   public static void main(String[] args) {}
}
c/c++代码中:
jfieldID g_propInt_id=0;
jfieldID g_propStr_id=0;
JNIEXPORT void JNICALL
Java_TestNative_initNativeIDs(JNIEnv* env,jobject clazz)
{
   g_propInt_id=GetFieldID(clazz,"propInt","I");
   g_propStr_id=GetFieldID(clazz,"propStr","Ljava/lang/String;");
}
JNIEXPORT void JNICALL
Java_TestNative_otherNative(JNIEnv* env,jobject obj)
{
   //可以直接使用下g_propInt_id和g_propStr_id的值了
}
------------------------------------------------
使用JNI的两个弊端
1、使用JNI,那么这个Java Application将不能跨平台,如果要移植别的平台上,那么native代码就需要重新编写。
2、java是强类型的语言,而c/c++不是,因此你必须在写JNI时更小心
总之,必须在构建java程序的时候,尽量少使用本地代码

相关文章推荐

JNI学习(五)、引用、缓存、异常、多线程

一、JNI中的引用问题 从java虚拟机创建的对象传到本地C/C++代码时会产生引用。根据Java的垃圾回收机制,只要有引用存在就不会触发该引用指向的Java对象的垃圾回收。 这些引用在JNI...

JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式

JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式

讲解JNI中的全局引用/局部引用/弱全局引用、缓存jfieldID和jmethodID的两种方式,并编写两种缓存方式的示例代码。 1.从Java虚拟机创建的对象传到本地C/C++代码时会产生引用...
  • sosesoA
  • sosesoA
  • 2016年06月21日 09:52
  • 664

JNI开发之缓存

前言:JNI缓存!

JAVA缓存技术-JNI静态文件的处理

在Java Web项目中,为了提高WEB应用的响应速度,可以把常用的静态文件(包括css,js和其他各种图片)提前读入到内存缓存中,这样可以减少很多文件系统的IO操作(这往往也是项目性能的瓶颈之一)。...

JNI由浅入深_8_JNI缓存字段和方法ID

获取字段ID和方法ID时,需要用字段、方法的名字和描述符进行一个检索。检索过程相对比较费时,因此本节讨论用缓存技术来减少这个过程带来的消耗。缓存字段ID和方法ID的方法主要有两种。两种区别主要在于缓存...

二级缓存软引用下载显示图片

  • 2013年05月06日 17:27
  • 174KB
  • 下载

Android NDK学习笔记13-JNI的局部和全局引用

局部引用    大多数JNI函数返回局部引用。局部引用不能在后续的调用中被缓存及重用,主要是因为它们的使用期限仅限于原生方法,一旦原生函数返回,局部引用即被释放。例如,使用FindClass函数返回一...

二级缓存软引用框架

  • 2013年05月07日 22:33
  • 110KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:JNI 引用与缓存
举报原因:
原因补充:

(最多只允许输入30个字)