dreakzts
dreakzts

Reputation: 11

The proper way to create a global map to hold multiple C++ objects in JNI

I am using TextureView and Vulkan to draw 3D models. I get the surface from the TextureView and pass it to the native side to render.

I need to support multiple TextureView to render different 3D models simultaneously, but I find out that my native .so library is only loaded once per process, suitable for memory saving.

So I think I need a global std::map in jni to hold different c++ objects. Every TextureView has an id and could use its id to find its c++ objects.

I was planning to code like this.

#include <jni.h>
#include <string>
#include <map>
#include <android/native_window_jni.h>
#include <android/asset_manager_jni.h>

std::unique_ptr<std::map<jint, MiuiVkWidgetApp*>> mVkWidgetAppMapUniquePtr;

extern "C" JNIEXPORT jboolean JNICALL
Java_com_miui_vkwidget_MiuiVkTextureView_nativeInitVkWidgetApp(JNIEnv* env, jobject  /* this */, jint id) {
    ...
    if (!mVkWidgetAppMapUniquePtr) {
        mVkWidgetAppMapUniquePtr.reset(new std::map<jint, MiuiVkWidgetApp*>());
    }
   ...
   return true;
}

extern "C" JNIEXPORT void JNICALL
Java_com_miui_vkwidget_MiuiVkTextureView_nativeDestroyVkWidgetApp(JNIEnv* /* env */,
                                                                  jobject /* this */, jint id) {
   mVkWidgetAppMapUniquePtr.reset(nullptr);
   ...
}

But in https://developer.android.com/training/articles/perf-jni#local-and-global-references "Local and global reference," it says that "The only way to get non-local references is via the functions NewGlobalRef and NewWeakGlobalRef." But NewGlobalRef seems only to support java objects.

I assume how I create the global map may have some potential risks, such as memory leak(I call DestroyVkWidgetApp when TextureView is onDestroy)? I am curious on how to create a proper global map in jni to hold multiple c++ objects? Thanks!

Upvotes: 0

Views: 87

Answers (1)

emandt
emandt

Reputation: 2708

JNI GlobalRefs refers to Java VM objects: those objects will persists in memory until a "destroy" method is called and Java could refers to them (if needed) in that period. Without GlobalRefs that object's memory could be freed early (by JVM GarbageCollector) and Java will FC due to memory issue.

It's seems that your JVM spawns multiple Processes, so if second process is spawn from the first one, yes you could use a "Mapped Memory File" starting from JavaVersion.VERSION_1_4 (JNI part could be copied from here: https://www.codeproject.com/Articles/2460/Using-Memory-Mapped-Files-and-JNI-to-communicate-b even if you don't need the Java one).

If processes are spawned from different Apps, I'm not sure but I think my solution will work.

(A "global map" is GLOBAL inside the same JVM (one Process per JVM), so even if you use a "global map" it will not be "seen" from the second Process but this last one will create its own "global map")

Upvotes: 0

Related Questions