我在使用Android JNI时遇到了问题。我从本机C调用一个java方法。一切正常,但几秒后APP崩溃,因为最多512个JNI引用的内容已满(或内存已满)。
这是我的代码:
int jniBluetoothSend( TJNIAdapter *pAdapter, byte *data, int dwLength )
{
JNIEnv *pEnv;
JavaVM *pVm = NULL;
jclass cls;
jmethodID methodId;
int nRet;
jbyteArray aData;
if ( pAdapter )
{
pVm = pAdapter->pVm;
( *pVm )->AttachCurrentThread( pVm, &pEnv, NULL );
if ( pAdapter->pClasses != NULL && pAdapter->pClasses->hgs_bluetooth != NULL )
{
// get function
methodId = ( *pEnv )->GetMethodID( pEnv, pAdapter->pClasses->hgs_bluetooth, "write", "([BI)I" );
if ( methodId )
{
aData = ( *pEnv )->NewByteArray( pEnv, dwLength);
( *pEnv )->SetByteArrayRegion( pEnv, aData, 0, dwLength, data);
// write Data to device
nRet = ( *pEnv )->CallIntMethod( pEnv, g_hgsBthObject, methodId, aData, dwLength );
// and delete Reference -> so GC can cleanup
( *pEnv )->DeleteLocalRef( pEnv, aData );
}
}
//( *pVm )->DetachCurrentThread( pVm ); -> // crashes as soon as getting called
}
return nRet;
}
每次调用“ReleaseByteArrayElements()”会在dalvik的Android日志中显示警告:
JNI: unpinPrimitiveArray(0x428e84a8) failed to find entry (valid=1)
所以,我认为,问题是,创建的数组没有被释放。但我不知道,如何以正确的方式做到这一点。
任何人都可以帮我吗? 谢谢!
修改
我做了几次测试。
如果我将DetachCurrentThread
函数添加到第二个if()的底部,则APP会崩溃,如果DetachCurrentThread
被调用的话。
但我在其他功能中添加了DeleteLocalRef
,APP不再崩溃。
所以我的问题是:我是否必须在我呼叫DetachCurrentThread
的每个功能中拨打AttachCurrentThread
,或者如果我将该呼叫一次发送到APP结尾就足够了吗?
还更新了代码
答案 0 :(得分:2)
每次
ReleaseByteArrayElements()
被调用时,dalvik都会在Android日志中显示警告:JNI:unpinPrimitiveArray(0x428e84a8)找不到条目(valid = 1)
ReleaseByteArrayElements
旨在与先前对GetByteArrayElements
的调用配对。来自Oracle's documentation:
发布< PrimitiveType> ArrayElements例程
void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);
一系列函数,通知VM本机代码不再需要访问elems。
elems
参数是使用相应的array
函数从Get<PrimitiveType>ArrayElements()
派生的指针。
由于您没有拨打GetByteArrayElements
,因此您也不应该致电ReleaseByteArrayElements
。
请注意,SetByteArrayRegion()
函数不是固定数组的函数之一,因此它不需要发布。