Issue
i have got a problem at using Android JNI. I call a java method from native C. Everything works fine, BUT after a few seconds the APP crashes, because the maximum of 512 entrys of JNI refs is full (or the memory is full).
Here is my code:
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;
}
Everytime "ReleaseByteArrayElements()" gets called a warning shows up in Android Log from dalvik:
JNI: unpinPrimitiveArray(0x428e84a8) failed to find entry (valid=1)
So, i think, the problem is, that the created array is not getting freed. But I don't know, how to do this in the right way.
Can anyone help me with this? Thanks!
EDIT
I have done a several tests.
If i add the DetachCurrentThread
function to the bottom of the second if(), the APP crashes, if DetachCurrentThread
is getting called.
But i have added DeleteLocalRef
in an other function, and the APP does not crash anymore.
So my question is: Do i have to call DetachCurrentThread
in every function i call AttachCurrentThread
or is it enough if i call that once to the end of the APP?
Also updated the Code
Solution
Everytime
ReleaseByteArrayElements()
gets called a warning shows up in Android Log from dalvik:JNI: unpinPrimitiveArray(0x428e84a8) failed to find entry (valid=1)
ReleaseByteArrayElements
is meant to be paired with a previous call to GetByteArrayElements
. From 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 fromarray
using the correspondingGet<PrimitiveType>ArrayElements()
function.
Since you didn't call GetByteArrayElements
you also shouldn't call ReleaseByteArrayElements
.
Note that SetByteArrayRegion()
function is not one of the functions that pin an array, therefore it does not require a release.
Answered By - Michael
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.