Android JNI ReleaseByteArrayElements 不起作用

Android JNI ReleaseByteArrayElements does not work

我在使用 Android JNI 时遇到问题。我从本机 C 调用了一个 java 方法。一切正常,但几秒钟后应用程序崩溃,因为 JNI refs 的最大 512 个条目已满(或内存已满)。

这是我的代码:

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()" 时都会在 Android 来自 dalvik 的日志中显示警告:

JNI: unpinPrimitiveArray(0x428e84a8) failed to find entry (valid=1)

所以,我认为问题是,创建的数组没有被释放。但我不知道,如何以正确的方式做到这一点。

谁能帮我解决这个问题? 谢谢!

编辑

我做了几个测试。 如果我将 DetachCurrentThread 函数添加到第二个 if() 的底部,如果 DetachCurrentThread 被调用,APP 会崩溃。

但是我在另外一个功能里添加了DeleteLocalRef,APP没有崩溃了。

所以我的问题是:我是否必须在调用 AttachCurrentThread 的每个函数中调用 DetachCurrentThread 或者如果我调用一次到 APP 结束就足够了吗?

也更新了代码

Everytime ReleaseByteArrayElements() gets called a warning shows up in Android Log from dalvik:

JNI: unpinPrimitiveArray(0x428e84a8) failed to find entry (valid=1)

ReleaseByteArrayElements 旨在与之前对 GetByteArrayElements 的调用配对。来自 Oracle's documentation:

Release<PrimitiveType>ArrayElements Routines
void Release<PrimitiveType>ArrayElements(JNIEnv *env, ArrayType array, NativeType *elems, jint mode);

A family of functions that informs the VM that the native code no longer needs access to elems. The elems argument is a pointer derived from array using the corresponding Get<PrimitiveType>ArrayElements() function.

因为你没有调用 GetByteArrayElements 你也不应该调用 ReleaseByteArrayElements.

请注意,SetByteArrayRegion() 函数不是固定数组的函数之一,因此不需要发布。