JNI related use record

JNI memory model

Java applications involving memory may be logically divided into two parts: Heap Memory and Native Memory.

Java applications are running Java Runtime Environment (JRE), whereas JRE itself from the Native languages (such as: C / C ++) to write programs.
(JVM only part of the JRE, JVM memory model belongs to another topic)

Therefore, this substantially comprises the relationship: (JRE (JVM (Heap Mem, Native Memory)))

  1. Heap Memory: for Java applications, all memory java objects are allocated from here, it is physically not continuous, but are logically contiguous. By initial and maximum values ​​may java command line parameters "-Xms, -Xmx" large set Heap.
  2. Memory Native: the Java Runtime process uses, there is no corresponding parameters to control the size , Runtime assigned by the operating system to process the available memory, the maximum size depends on the operating system process.

The main role of Native Memory is as follows:

  • Java heap management state data (for the GC);
  • JNI calls, Stack is Native, JNI memory allocation is actually a great relationship with the Memory Native ;
  • When using Native Memory JIT compiler, and JIT input (Java byte codes) and an output (executable code) are also stored in the Native Memory;
  • NIO direct buffer;
  • Thread resources.

JNI memory and reference

  • In Java code, Java objects are stored in the JVM Java Heap, automatically recovered by the garbage collector (Garbage Collector, i.e., GC) to be.
  • In Native code, memory is allocated from Native Memory, the memory required to operate in accordance with Native programming specifications. Such as: C / C ++ using malloc () / new allocation of memory, the use of manually free () / delete reclaim memory.

However, both JNI and above it, some differences .

Java provides the JNI corresponding reference type (eg: jobject, jstring, jclass, jarray, jintArray etc.), so that code can access the Java Native object via JNI functions.

  • Java object reference points to is usually stored in the Java Heap,
  • The Native code that holds references are stored in Native Memory in.

For example, the following code:

jstring jstr = env->NewStringUTF("Hello World!");
  1. jstring JNI types are provided, corresponding to the Java String type
  2. NewStringUTF JNI function () is used to construct a String object that is stored in the Java Heap and returns a reference to a type of jstring.
  3. String objects stored in the references in jstr, jstr Native is a local variable, stored in Native Memory in .

In order to avoid OOM exceptions and memory leak occurs when the JNI during our development, it needs to be familiar with memory allocation and management.

JNI reference types

JNI reference types, there are three: Local Reference, Global Reference, Weak Global Reference.

The following were cited to explain these three memory allocation and management.

Local Reference

Local Reference Native Method exists only when executed.

It is beginning to create a lifetime in the implementation of the Native Method in Native Method completes switch back to Java code, all Local Reference is deleted, the end of life (DeleteLocalRef can call ahead of the end of its lifetime).

Whenever a thread context switch to a Java Native code environment from, JVM will allocate a block of memory used to create a Local Reference Table, the Table created to store all Local Reference Method Native this execution , so Local Reference does not belong to Native Code local variables .

Whenever Native code when a reference to a Java object, JVM will create a Local Reference Table in this .

For example jstring jstr = env->NewStringUTF("Hello World!");, we call NewStringUTF () after creating a String object in Java Heap, the Local Reference Table in the corresponding'll add a Local Reference.

Local Reference schematic

  • jstr stored in the Native Method Stack, is a local variable;
  • Then point Heap Mem by Local Reference Table in localRef, Local Reference Table is transparent to us;
  • Local Reference Table memory is small, the number of Local Reference can be stored is limited, improper use can cause abnormal OOM ;
  • At the end of Native Method, JVM will automatically release Local Reference, but if circulation or other situations in development to create a large number of Local; Reference, should be timely use DeleteLocalRef () Reference delete unnecessary Local , Local Reference Table is to avoid bursting at the seams.
  • Local Reference Native not inside the local variables, local variables in a stack, and stored in the Local Reference Local Reference in the Table.
  • Parameters DeleteLocalRef () is a reference type jobject, for the average basic data types (such as: jint, jdouble, etc.), it is not necessary to call this function deleted, but like jstring, jintArray, jobject on these needs.
/**
 * 删除localRef所指向的局部引用。
 * @localRef localRef:局部引用
*/
voi DeleteLocalRef(jobject localRef);

 

Note Local Reference of the life cycle, and if takes a long time to hold a Native Java objects, the store can not be used in the jobject Native, or use the next time, even if the same thread call will also be unavailable.

Here is the wrong approach:

class MyPeer {
public:
    MyPeer(jstring s) {
        str_ = s; // Error: stashing a reference without ensuring it’s global.
    }
    jstring str_;
};

static jlong MyClass_newPeer(JNIEnv* env, jclass) {
    jstring local_ref = env->NewStringUTF("hello, world!");
    MyPeer* peer = new MyPeer(local_ref);
    return static_cast<jlong>(reinterpret_cast<uintptr_t>(peer));
    // Error: local_ref is no longer valid when we return, but we've stored it in 'peer'.
}

static void MyClass_printString(JNIEnv* env, jclass, jlong peerAddress) {
    MyPeer* peer = reinterpret_cast<MyPeer*>(static_cast<uintptr_t>(peerAddress));
    // Error: peer->str_ is invalid!
    ScopedUtfChars s(env, peer->str_);
    std::cout << s.c_str() << std::endl;
}

The correct approach is to use Global Reference, as follows:

class MyPeer {
public:
    MyPeer(JNIEnv* env, jstring s) {
        this->s = env->NewGlobalRef(s);
    }
    ~MyPeer() {
        assert(s == NULL);
    }
    void destroy(JNIEnv* env) {
        env->DeleteGlobalRef(s);
        s = NULL;
    }
    jstring s;
};

Global Reference

After understanding the Local Reference, and come to understand Global Reference Weak Global Reference much easier.

Global Reference and Local Reference difference is that the life cycle and scope:

  1. Global Reference is to create and delete through JNI function NewGlobalRef () and DeleteGlobalRef ().
  2. Global Reference are global, you can use multiple Native Method calls and process multiple threads , before the initiative to call DeleteGlobalRef, it continues to be valid (GC does not reclaim its memory).
/**
 * 创建obj参数所引用对象的新全局引用。
 * obj参数既可以是全局引用,也可以是局部引用。
 * 全局引用通过调用DeleteGlobalRef()来显式撤消。
 * @param obj 全局或局部引用。
 * @return 返回全局引用。如果系统内存不足则返回 NULL。
*/
jobject NewGlobalRef(jobject obj);

/**
 * 删除globalRef所指向的全局引用
 * @param globalRef 全局引用
*/
void DeleteGlobalRef(jobject globalRef);

Weak Global Reference

Weak Global Reference be created and deleted with NewWeakGlobalRef () and DeleteWeakGlobalRef ().

It differs from the Global Reference that refers to that type at any time are likely to be recovered GC.

For Weak Global Reference, by isSameObject () to compare it with NULL, to see if that has been recovered.

If the return JNI_TRUE, it means that has been recovered, the need to re-initialize the weak global reference.

/**
 * 判断两个引用是否引用同一Java对象。
 * @param ref1 Java对象
 * @param ref2 Java对象
 * @retrun 如果ref1和ref2引用同一Java对象或均为 NULL,则返回 JNI_TRUE。否则返回 JNI_FALSE。
*/
jboolean IsSameObject(jobject ref1, jobject ref2);

Weak Global Reference timing recovery is uncertain, it is possible to determined the previous line of code it is available, after the line of code was recovered out GC.

In order to avoid these things happening, JNI official gives the correct approach to get Weak Global Reference by NewLocalRef (), to avoid being recovered GC.

Sample code is as follows:

static jobject weakRef = NULL;

JNIEXPORT void JNICALL Java_com_bassy_jnitest_Main_getName(JNIEnv *env, jobject instance) {

jobject localRef;
//We ensure create localRef success        
while(weakRef == NULL || (localRef = env->NewLocalRef(weakRef)) == NULL){
    //Init weak global reference again
    weakRef = env->NewWeakGlobalRef(...)
}
//Process localRef
//...
env->DeleteLocalRef(localRef);
}

reference

JNI memory management

Guess you like

Origin www.cnblogs.com/stillcoolme/p/11242602.html