unpinPrimitiveArray: failed to find entry

2,429 views
Skip to first unread message

Miha

unread,
Aug 2, 2011, 8:39:15 AM8/2/11
to android-ndk
Hi!

In my native method, I'm calling into Java. I am creating a byte array
from an existing byte[] in native code and I am setting this byte[] to
pair in a HashMap.

When trying to release, I get:
08-02 14:29:18.252: WARN/dalvikvm(4338): JNI:
unpinPrimitiveArray(0x40922120) failed to find entry (valid=1)

Why is that? Is my code leaking array reference? I am monitoring gc
output and memory consumption is stable....

The code (edited for brevity): (alternatively: http://pastebin.com/4KeGu3LN)

LOGD("Size of image: %d", data->byteCount);
jbyteArray imageBuf = p_env->NewByteArray(data->byteCount);
p_env->SetByteArrayRegion(imageBuf, 0, data->byteCount, (jbyte*)data-
>buffer); (data->buffer contains byte[])
jobject imageHashmap = jni_helpers_HashMap_create(p_env); // creates
HashMap using NewObject
jstring key = p_env->NewStringUTF("data");
jni_helpers_HashMap_put(p_env, imageHashmap, key, imageBuf); // call
put method on a HashMap instance
p_env->DeleteLocalRef(key);
key = p_env->NewStringUTF("width");
jobject intVal = jni_helpers_create_Integer(p_env, data->width);
jni_helpers_HashMap_put(p_env, imageHashmap, key, intVal);
p_env->DeleteLocalRef(key);
p_env->DeleteLocalRef(intVal);
key = p_env->NewStringUTF("height");
intVal = jni_helpers_create_Integer(p_env, data->height);
jni_helpers_HashMap_put(p_env, imageHashmap, key, intVal);
p_env->DeleteLocalRef(intVal);
p_env->DeleteLocalRef(key);
p_env->CallVoidMethod(g_callbackTarget, g_callbackMethod, EVENT_ID,
(jobject)imageHashmap);
LOGD("Cleaning up resources...");
p_env->ReleaseByteArrayElements(imageBuf, (jbyte*)data->buffer,
JNI_ABORT); // <!-- this is where I get the message
p_env->DeleteLocalRef(imageBuf);
p_env->DeleteLocalRef(imageHashmap);

fadden

unread,
Aug 4, 2011, 7:48:42 PM8/4/11
to android-ndk
On Aug 2, 5:39 am, Miha <miha.valen...@gmail.com> wrote:
> When trying to release, I get:
> 08-02 14:29:18.252: WARN/dalvikvm(4338): JNI:
> unpinPrimitiveArray(0x40922120) failed to find entry (valid=1)
>
> Why is that? Is my code leaking array reference? I am monitoring gc
> output and memory consumption is stable....
[...]
> jbyteArray imageBuf = p_env->NewByteArray(data->byteCount);
> p_env->SetByteArrayRegion(imageBuf, 0, data->byteCount, (jbyte*)data->buffer); (data->buffer contains byte[])
[...]
> p_env->ReleaseByteArrayElements(imageBuf, (jbyte*)data->buffer,
> JNI_ABORT); // <!-- this is where I get the message

You only need to call ReleaseByteArrayElements if you previously
called GetByteArrayElements. The warning message is saying that it's
not finding the array in the pinned-array list, which makes sense.

Miha

unread,
Aug 5, 2011, 2:38:50 PM8/5/11
to android-ndk
On Aug 5, 1:48 am, fadden <fad...@android.com> wrote:
> On Aug 2, 5:39 am,Miha<miha.valen...@gmail.com> wrote:
>
> > When trying to release, I get:
> > unpinPrimitiveArray(0x40922120) failed to find entry (valid=1)
> > jbyteArray imageBuf = p_env->NewByteArray(data->byteCount);
> > p_env->SetByteArrayRegion(imageBuf, 0, data->byteCount, (jbyte*)data->buffer); (data->buffer contains byte[])
> > p_env->ReleaseByteArrayElements(imageBuf, (jbyte*)data->buffer,
> You only need to call ReleaseByteArrayElements if you previously
> called GetByteArrayElements.  The warning message is saying that it's
> not finding the array in the pinned-array list, which makes sense.

Thanks!

I thought that if I'm setting it, I should also be releasing it.

Regards,
Miha.

Stephen Williams

unread,
Aug 6, 2011, 3:41:41 AM8/6/11
to andro...@googlegroups.com
This bounced the first time.

On Fri, Aug 5, 2011 at 7:52 PM, Stephen Williams <stephend...@gmail.com> wrote:
You have to read between the lines a bit in the Sun/Oracle documentation to understand exactly what's going on:

"GetByteArrayElements()" should have been called "PinAndReturnPointerToArrayElementsData()" and "ReleaseByteArrayElements()" should have been called "UnpinByteArrayElementsDataPointer()".  Where "pinning" refers to locking against GC moving of the data of a Java object, different from locking / synchronization of use between threads.

NewByteArray() creates a new array (or you could have been passed one created in Java).  "Releasing" such a reference has to do with deleting local (or potentially global) references, not the "Release...ArrayElements" calls.
{Get,Set}ByteArrayRegion does a lock/copy/unlock in one step (and, if JNI copying were involved, have the advantage of only operating on a subset of the whole array).

All of these interfaces allow the Java objects to be moved during GC when they aren't locked.  The interfaces also allow an implementation or mode where the JNI interface has to copy and somehow transform the data native representation between native and Java.  This would happen during pin/unpin (Get/Release<type>ArrayElements).  Few or no current implementations need to do this, which is good for performance because it would add an extra copy (or worse) in both directions.

In my code, that uses JavaGlue to create the JNI glue and provide some utility methods, I write Java/C++ code (Java++?) like this:

// This code does not copy the byte array.
// Java:
ByteArray buf = new ByteArray(x*y*4);  // Just a byte[] plus some methods.
BytePointer bp = buf.pin()
int result = someCppObject.someCppMethod(bp, x*y*4); // Calling C++ code directly that doesn't know anything about JNI or Java.
buf.unpin();

Or for a method like:
// This code copies the C++ bytes into a new Java byte[]
// C++:
typedef ByteVector Vector<unsigned char *>;
ByteVector Clazz::returnByteVector();

// Java:
ByteArray ba = ByteArray.byteArray(ob.returnByteVector());
byte[] bytes = ba.getByteArray();

This works well in a heavily multi-threaded, real-time, animated GUI environment.

If Bitmap just exposed its byte[] data, I'd be very happy.  The jnigraphics mechanism is roughly equivalent, but clumsy by comparison.

Even called many (dozens to hundreds) times per second, JNI overhead is insignificant.  At least when done in the most efficient way, this should be true: Both Android/Dalvik and the JDK constantly call native code to accomplish useful things.  Obviously true for system calls, but also for nearly all graphics and similar bulk operations.

sdw



--
--
Stephen D. Williams s...@lig.net scie...@gmail.com LinkedIn: http://sdw.st/in
V:650-450-UNIX (8649) V:866.SDW.UNIX V:703.371.9362 F:703.995.0407
AIM:sdw Skype:StephenDWilliams Resume: http://sdw.st/gres
Personal: sdw.st facebook.com/sdwlig twitter.com/scienteer
Reply all
Reply to author
Forward
0 new messages