jigarzon
jigarzon

Reputation: 1228

Android NDK JNI array reference table overflow

I have two functions and I'm getting a ReferenceTable overflow. The summary of consumed array entries is:

     1 of byte[] (3 elements)
   446 of byte[] (75 elements) (2 unique instances)
   576 of byte[] (147 elements) (2 unique instances)
     1 of int[] (25 elements)

I really checked the code to find any mistake, but didn't found it. Im releasing arrays after getting them. The only thing is that these functions are called thousands of times, can this be the cause?

Here is all my native code:

called once:

JNIEXPORT void JNICALL Java_ar_com_teasoft_Image_nativeUnlock(
            JNIEnv *env, jclass clazz, jobject bitmap) {
        AndroidBitmap_unlockPixels(env, bitmap);
    }

called once:

JNIEXPORT jlong JNICALL Java_ar_com_teasoft_Image_nativeLock(
        JNIEnv *env, jclass clazz, jobject bitmap) {
    int ret;
    AndroidBitmapInfo info;
    if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
        LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
        return 0;
    }
    if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
        LOGE("Bitmap format is not RGBA_8888!");
        return 0;
    }
    void* bitmapPixels;
    if ((ret = AndroidBitmap_lockPixels(env, bitmap, &bitmapPixels)) < 0) {
        LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
        return 0;
    }
    return (jlong) bitmapPixels;

}

called lots of times:

JNIEXPORT void JNICALL Java_ar_com_teasoft_Image_nativeCopyPixels(
        JNIEnv *env, jclass clazz, jlong dataRef, jintArray sourceIndexes,
        jintArray targetIndexes, jint count) {
    argb* sourcePixels;
    argb* targetPixels;
    jint *sourceArray = env->GetIntArrayElements(sourceIndexes, NULL);
    jint *targetArray = env->GetIntArrayElements(targetIndexes, NULL);
    for (int i = 0; i < count; i++) {
        sourcePixels = (argb*)((char*) dataRef + sourceArray[i] * 4);
        targetPixels = (argb*)((char*) dataRef + targetArray[i] * 4);
        (*targetPixels) = (*sourcePixels);
    }
    env->ReleaseIntArrayElements(sourceIndexes, sourceArray, JNI_ABORT);
    env->ReleaseIntArrayElements(targetIndexes, targetArray, JNI_ABORT);

    }

called lots of times:

JNIEXPORT void JNICALL  Java_ar_com_teasoft_Image_nativeGetRGB(
        JNIEnv *env, jclass clazz, jlong dataRef, jintArray indexes,
        jbyteArray destRgb) {
    jint *array = env->GetIntArrayElements(indexes, NULL);
    jbyte *dstarray = env->GetByteArrayElements(destRgb, NULL);
    int size = env->GetArrayLength(indexes);
    char* sourcePixels;
    int dstCount = 0;
    for (int i = 0; i < size; i++) {
        sourcePixels = (char*) dataRef + array[i] * 4;
        dstarray[dstCount++] = (*(sourcePixels + 1));
        dstarray[dstCount++] = (*(sourcePixels + 2));
        dstarray[dstCount++] = (*(sourcePixels + 3));
    }
    env->ReleaseIntArrayElements(indexes, array, JNI_ABORT);
    env->ReleaseByteArrayElements(destRgb, dstarray, JNI_COMMIT);
}

Based on the summary, it looks like the one that is not released, is of byte[], so it has to be the one in function nativeGetRGB. But i cannot find where the mistake is.

Please Help! Regards, Juan Ignacio

Upvotes: 1

Views: 1201

Answers (1)

Sam
Sam

Reputation: 7868

Java_ar_com_teasoft_Image_nativeGetRGB():

As far as I can see, you'd need to commit and free any temporary array copy by passing 0 instead of JNI_COMMIT to ReleaseByteArrayElements(). The second argument of Get*ArrayElements() is a pointer to a boolean, which will be set to true, if the returned array is a copy, instead of pinned memory.

Java_ar_com_teasoft_Image_nativeCopyPixels():

You might also want to pass 0 instead of JNI_ABORT, which discards everything, here:

env->ReleaseIntArrayElements(targetIndexes, targetArray, JNI_ABORT);

The tricky thing with arrays is, that the release mode applies to copied arrays only, since pinned memory gets modified directly. There's no way to force either array copy or pinning.

Upvotes: 2

Related Questions