Local reference and global reference knowledge of JNI memory management

Time:2021-3-6

Recently, we have encountered some problems related to JNI reference in the development process. We have learned the relevant knowledge points of local reference and global reference

background: project requirements, call the upper Android camera java interface in native C / C + + layer, and implement all operations including camera in native layer. However, in the process of JNI debugging, Android JNI error (APP Bug): accessed stale local reference was reported.

phenomenon: create a Java camera object in the native layer, save the pointer of the object locally, return the function to the Java layer, and then enter the native layer. You want to call the corresponding method through the camera object pointer of the native layer, but find that every time you call the Java object method again, an error is reported.

analysis: for a Java object created in the native layer, there will be a local reference to the object after the object is created. When the local reference is returned from the native environment to the Java environment, the local reference is invalid, and the object has no reference count. Java’s memory recycling mechanism will automatically recycle the object, and an error will be reported when it enters the native layer to access its previously saved address for the second time.

solve: use global reference to always hold the reference of the object so that it will not be automatically recycled. Please see the following knowledge points.

Local Reference

For local references, see the following simplified code:

env->NewStringUTF("0"); 

In JNI, every time the newobject method is called to create a new object, a local reference to the object is returned The local reference is only valid in the thread’s current native environment. After returning to the Java environment, the connection between the reference and the object will be broken, and the reference will be invalid. Therefore, we cannot use the local reference cache in the native method for the next call.

Can local references be created infinitely

As shown in the figure:

Local reference and global reference knowledge of JNI memory management

The concept of local reference table is introduced here. Every time a thread enters the native environment from the Java environment, the JVM will create a local reference table of the thread’s native environment to save all the local references created by the native environment. Every time a Java object is referenced in the native environment or a new Java object is created, the JVM will create a local reference table. The local reference table has a size limit System, the maximum is 512, if more than the limit will report oom memory leak.

Q: So how can we better avoid OO in native environment due to too many local references?

A: Control the life cycle of local references. If you need to create too many local references, you can manually call the deletelocalref function to delete the local reference after the operation of Java objects. The local reference will be removed from the local reference table to avoid triggering the size limit of the local reference table.

be careful: a local reference is not a local variable in the code that we usually understand. A local variable will be invalid after the end of the current life cycle (for example, the exit of a function). A local reference may not be invalid after the exit of a function. Its life cycle is associated with the entire native context environment. Only when it returns from the native environment to the Java environment, the local reference will be invalid.

Global Reference

Global reference finally comes to the problem discussed above, because local reference will be invalid after the native environment returns to the Java environment. As a result, when the corresponding Java object is used again in the native environment, an error will occur. Therefore, global reference can be used to solve this problem. Global reference can always keep in touch with the Java object, so that the object will not be recycled by the JVM See the following code:

JNIEXPORT jint JNICALL JNI_OnLoad (JavaVM * vm, void * reserved) {  
    jclass tmp = env->FindClass("com/example/company/MyClass");  
    jclass class = env->NewGlobalRef(tmp);
    return JNI_VERSION_1_6;  
}

It should be noted here that after Java objects are not needed, the deleteglobalref() function should be called manually as far as possible to make the reference invalid, so as to avoid the existence of objects and potential memory leakage.

Weak Global Reference

The difference between virtual global reference and global reference is that the reference of this type may be recycled by JVM at any time

NewWeakGlobalRef();
DeleteWeakGlobalRef();
isSameObject();

Before using a virtual reference, you need to compare it with null through issameobject. If true is returned, it means that it has been recycled by the JVM and cannot be used. Here, it is possible that the first line of code is still available, and the next line of code is recycled by the JVM. The solution is to obtain a virtual global reference through newlocalref() to avoid being recycled by the JVM at that time.

reference material

https://www.cnblogs.com/zhong…
https://www.cnblogs.com/young…
https://stackoverflow.com/que…
https://www.ibm.com/developer…
https://juejin.im/post/5c19bf…

Please pay attention to more articles

Local reference and global reference knowledge of JNI memory management

More articles, please pay attention to my v x Princess number: program meow adult, welcome to exchange.