JAVA有个垃圾回收机制,没有引用的对象会被虚拟机在整理内存时进行回收,所以使用弱引用java对象时,而实际调用为持久对象时将会出现问题。并且这个问题有时会随机出现,这个会内存整理回收时机有关。

下面,说下对于在JNI中使用JAVA中对象代码编写方法:


JAVA类方法编写:

public class TestModule{
	static native boolean native_init(WeakReference<TestModule> wo);
	
	/* 构造函数中传递JAVA弱应用对象给JNI层 */
	public TestModule() {
		native_init(new WeakReference<TestModule>(this));
	}

	...
	
	/* 提供给JNI调用的JAVA方法 */
	static String native_callback(Object wo, int i, String json) {
		try {
			WeakReference<CDCAModule> r = (WeakReference<TestModule>) wo;
			CDCAModule m = r.get();
			if (m != null)
				return m.callback.callback(i, json);
		} catch (Throwable e) {
			e.printStackTrace();
		}
		return null;
	}
}


JNI 编写方法:

static jobject   g_java_peer = NULL;
static jmethodID g_callback = NULL;

/* 对应JAVA层native_init函数 */
JNIEXPORT jboolean JNICALL Java_com_test_TestModule_native_init(JNIEnv *e,
		jclass clazz, jobject wo) {
	if (wo == NULL)
		throw_runtime_exception(e, "");
		
	/**
	 * 如果这个JAVA对象,垃圾回收时不予释放掉,使用弱引用转换成强引用对象,如此
	 *  则仅用户进行主动释放时此对象才无效
	 */
	if (g_java_peer == NULL)
		g_java_peer = e->NewGlobalRef(wo);

	/* 获取得到JAVA中定义的方法 */
	if ((g_callback = e->GetStaticMethodID(clazz, "native_callback",
			"Ljava/lang/Object;ILjava/lang/String")) == NULL)
		return JNI_FALSE;
	return JNI_TRUE;
}

char*jniCallJavaTestModuleMethod(int id, const char*json, char*buf, int len) {
	JNIEnv*e = NULL;
	jstring ret = NULL;
	char *p = NULL;
	int rlen;

	if (id < 0 || buf == NULL || len <= 0)
		return NULL;
	/* 这里注意,JNIEnv是一个线程相关的变量,所以使用javaAttachThread保证取得当前线程的Jni环境变量*/
	if ((e = javaAttachThread("test-thread")) == NULL)
		return NULL;
		
	/* 调用JAVA方法 */
	if ((ret = (jstring) e->CallStaticObjectMethod((jclass)g_java_peer, g_callback,
			json ? e->NewStringUTF(json) : NULL)) == NULL)
		return NULL;
	p = buf;
	if ((rlen = e->GetStringLength(ret)) > len) {
		char*p = (char*)calloc(1,rlen);
		if (p == NULL)
			return NULL;
	}
	e->GetStringUTFRegion(ret, 0, rlen, p);
	return p;
}


在JNI中提供三种类型的引用:

1、Local Reference 本地引用,函数调用时传入jobject或者jni函数创建的jobejct,其特点就是一旦JNI层函数返回,jobject就被垃圾回收掉,所以需要注意其生命周期。可以强制调用DeleteLocalRef进行立即回收。

       jstring pathStr = env->NewStringUTF(path)

       ....

env->DeleteLocalRef(pathStr);


2、Global Reference 全局引用 ,这种对象如不主动释放,它永远都不会被垃圾回收

      创建: env->NewGlobalRef(obj);

      释放: env->DeleteGlobalRef(obj)


3、Weak Global Reference 弱全局引用,一种特殊的 Global Reference ,在运行过程中可能被垃圾回收掉,所以使用时请务必注意其生命周期及随时可能被垃圾回收掉,比如内存不足时。

使用前可以利用JNIEnv的 IsSameObject 进行判定它是否被回收

env->IsSameObject(obj1,obj2);


Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐