Search code examples
androidarraysandroid-ndkjava-native-interfacelimit

Android passing large float arrays from native to java via jni. Getting error if over certain size


I am wanting to pass a single large array of floats anywhere up too and beyond float[100000]. I have a setup successfully passing an array of size 212. But any larger and it crashes giving the following error message in the logcat:

"Fatal signal 11 (SIGSEGV) at 0xbe949000 (code=1)"

My code

Native function

NIEXPORT jfloatArray JNICALL  Java_carron_graphics_benchmark_NativeWrapper_getArrayNative(JNIEnv * env, jclass cls) {

    int tempSize = mParticleSystem->mSizeOfSystem*2;

    jfloat cArray[tempSize];
    jsize len = sizeof(cArray);

    jfloatArray jArray = (*env).NewFloatArray(len);

    if (jArray != NULL) {

        jint i;

        for (i = 0; i < tempSize; i++) {
            cArray[i] = mParticleSystem->mParticlePositions[i];
        }
        (*env).SetFloatArrayRegion(jArray, 0, len, cArray);
    }
    return jArray;
}

Java Pretty straight forward simply grabbing the array. If I create and pass a float array larger than 212 though I get the error as shown above.

float tempArray[] = NativeWrapper.getArrayNative();

Has anyone encountered this problem or can see how I can get around this limit? Also I apologise if this question has been answered already, I could not find this specific issue nor an answer. Any help will be appreciated :)

EDIT:

For updating a global jfloatArray to avoid the garbage collector when frequently fetching an array through jni.

static jfloatArray gArray = NULL;

JNIEXPORT jfloatArray JNICALL Java_carron_graphics_benchmark_NativeWrapper_getArrayNative(JNIEnv * env, jclass cls)  {
    int arrayLength = mParticleSystem->mSizeOfSystem*2;

    if (gArray == NULL)
    {
        // create array
        jfloatArray jArray;
        jArray = env->NewFloatArray(arrayLength);
        gArray = (jfloatArray)env->NewGlobalRef(jArray);
    }

    // Update global 
    env->SetFloatArrayRegion(gArray, 0, arrayLength, mParticleSystem->mParticlePositions);

    return gArray;
}

Solution

  • Problem with your code is that stack is limited in size. You can not put there large arrays (jfloat cArray[tempSize] variable). If you want to create large array, do that on heap, like Alex is showing you.

    If mParticleSystem->mParticlePositions is float array then this code will be better:

    int tempSize = mParticleSystem->mSizeOfSystem*2;
    jfloatArray jArray = env->NewFloatArray(tempSize);
    
    if (jArray != NULL)
    {
        env->SetFloatArrayRegion(jArray, 0, tempSize, mParticleSystem->mParticlePositions);
    }
    return jArray;
    

    If it is not float array then use following code, no need to create additional float array:

    int tempSize = mParticleSystem->mSizeOfSystem*2;
    jfloatArray jArray = env->NewFloatArray(tempSize);
    
    if (jArray != NULL)
    {
        if (float* ptr = env->GetFloatArrayElements(jArray, NULL))
        {
            for (int i=0; i<tempSize; i++)
            {
                ptr[i] = mParticleSystem->mParticlePositions[i];
            }
            env->ReleaseFloatArrayElements(jArray, ptr, JNI_COMMIT);
        }
    }
    
    return jArray;
    

    EDIT

    To store jArray somewhere else (for example globally) do following:

    static jfloatArray gArray = NULL;
    
    jfloatArray fun(...)
    {
        jfloatArray jArray;
    
        if (gArray == NULL)
        {
            // create array
            jArray = env->NewFloatArray(tempSize);
            gArray = (jfloatArray)env->NewGlobalRef(jArray);
        }
        else
        {
            jArray = gArray;
        }
    
        // ... here fill/modify jArray
        // SetFLoatArrayRegion/GetFloatArrayElemeents/ReleaseFloatArrayElements
    
        return jArray;
    }
    

    When done free the memory:

    void freeArray(...)
    {
        env->DeleteGlobalRef(gArray);
        gArray = NULL;
    }