Parsing object reference and memory leak in Java JNI programming

JNI, Java Native Interface, is the programming interface of native code. JNI enables Java code programs to interact with native code -- calling native code in Java programs. Embed the code of Java virtual machine calling Java in the native code. JNI programming is widely used in software development, and its advantages can be summarized as follows: making use of the platform relevance of native code to highlight its advantages in platform related programming. Code reuse of native code. Native code is the underlying operation, which is more efficient. However, everything has two sides, and so does JNI programming. When using JNI, programmers should recognize the following disadvantages in JNI programming, develop strengths and avoid weaknesses, and then they can write more perfect and high-performance Code: the context switching from Java environment to native code is time-consuming and inefficient. JNI programming, if not operated properly, may cause the collapse of Java virtual machine. JNI programming, if operated improperly, may cause memory leakage. Memory leakage in JAVA memory leakage in Java programming can be divided into two types from the perspective of leaked memory location: memory leakage in Java heap in JVM; Memory leak of native memory in JVM memory.

Local and global references

JNI exposes instances and array types as opaque references. Native code never directly checks the context of an opaque reference pointer, but uses JNI functions to access the data structure pointed to by the opaque reference. Because only opaque references are processed, there is no need to worry about the layout of different internal objects caused by different Java VM implementations. However, it is still necessary to understand the different kinds of references in JNI: 1) JNI supports opaque references in 3: local references, global references and weak global references. 2) Local and global references have different lifecycles. Local references can be released automatically, while global references and global references are valid until released by programmer. 3) A local or global reference that prevents the mentioned object from being garbage collected. Weak global references allow garbage collection of the mentioned objects. 4) Not all references can be used in all contexts. For example, it is illegal to use a local reference after creating a return reference native method.

So what are local references, what are global references, and how are they different?

Local reference

Most JNI functions create local references. For example, the JNI function newobject creates an instance and returns a local reference to the instance.

A local reference is valid only in the dynamic context of the native method that created it, and only in a single call to the native method. All local references are valid only during the execution of a native method and are recycled when the method returns.

It is not feasible to use a static variable in the native method to save a local reference so that it can be used in subsequent calls. For example, the following example misuses a local reference: / * this code is illegal * / jstring

This way of saving local references is incorrect because findclass () returns a reference to Java Local reference to lang.string. This is because when the native code returns and exits from mynewstring, the VM will release all local references, including references to class objects stored in the stringclass variable. In this way, when calling mynewstring again, the illegal address may be accessed, resulting in memory corruption or system crash.

There are two ways to invalidate local references: '1) the system will automatically release local variables. 2) Programmers can explicitly manage the life cycle of local references, such as calling deletelocalref.

A local reference may be passed to multiple native methods before being destroyed. For example, in mynewstring, a string reference created by newobject is returned, and the caller of newobject will decide whether to release the reference. In the following code:

Received from Java at VM_ C_ After the local reference of F, the base string object is passed to Ava_ C_ The caller of F then destroys the local reference created by the JNI function NewObject originally called by Mynewstring.

Local objects belong only to the thread that created them and are valid only in that thread. Local references created by a thread that wants to call another thread are not allowed. It is wrong programming to save a local reference to a global variable and then use it in other threads.

Global reference

Between multiple calls to a native method, a global reference can be used to span them. A global reference can span multiple threads and is consistently valid until released by the programmer. Like local references, global references ensure that referenced objects will not be garbage collected.

Unlike local references (local variables can be created by most JNI functions), global references can only be created by one JNI function (newglobalref). Here is a mynewstring using the global reference version: / * this code is OK * / jstring

Weak global reference

The weak global reference is in Java 2 sdk1 2. It is created by the newgolableweakref function and destroyed by the deleteglobalweakref function. Like global references, it can be called across native methods or across different threads. However, unlike global references, it does not prevent garbage collection of underlying objects. The following is the mynewstring of the weak global reference version:

JNIEXPORT void JNICALL

Weak global references are useful when a reference cached by native code does not want to prevent the underlying object from being garbage collected. As in the above example, mypkg MyCls. F needs to cache mypkg A reference to mycls2. By setting mypkg Mycls2 is cached in the weak reference, and the class that can implement mycls2 can still be unloaded.

In the code above, We assume that the life cycle of mycls class and mycls2 class is the same (for example, it is loaded and unloaded in the same class). Therefore, it is not considered that mycls2 is unloaded and then reloaded when java_mypkg_mycls_f, the implementation of class mycls and native methods, will continue to be used. For the case that this mycls2 class may be unloaded and reloaded, it is necessary to check whether the weak global reference is still valid when using. How to check Cha, this will be mentioned below.

Compare references

You can use the JNI function issameobject to check whether two given local references, global references or weak global references point to the same object. (* Env) - > issameobject (Env, obj1, obj2) return value: JNI_ True indicates that two objects are consistent and are the same object. JNI_ False indicates that two objects are inconsistent and not the same object.

In Java VM, null is a null reference. If an object obj is a local reference or a global reference, you can check whether it points to a null object:

Or:

For weak global references, the above rules need to be changed: we can use this function to judge whether the object pointed to by a non-0 weak global reference wobj is still alive (still valid).

Return value: JNI_ True indicates that the object has been recycled. JNI_ False indicates that the object wobj points to is still valid.

Releasing references not only takes up memory for the referenced objects, but also consumes some memory for each JNI reference itself. As a JNI programmer, you should know the number of references that the program will use in a given period of time. In particular, although the local references created by the program will eventually be automatically released by the VM, it is still necessary to know the upper limit of the number of local references created at any time during the execution of the program. Creating too many references, even if they are transient, can lead to memory exhaustion.

In most cases, when executing a native method, you don't need to worry about releasing the local reference. The Java VM will release it when the native method returns the caller. However, it is sometimes necessary for JNI programmers to release local references to avoid excessive memory use. So when do you need to display the release? Let's take a look at the scenario: 1) a large number of local references are created in a single native method call. This may cause JNI local reference table overflow. At this time, it is necessary to delete those local references that are no longer used in time. For example, the following code, in this loop, it is possible to create a huge string array each time. After each iteration, the native code needs to explicitly release the local reference to the string element:

2) You may want to create a tool function that will be called in an unknown context. For example, the example of mynewstring mentioned earlier releases the local reference in time every time the caller is returned.

3) The native method may not return (for example, a method that may enter the loop of infinite event distribution). At this time, it is very important to release the local reference in the loop so that it will not accumulate indefinitely, resulting in memory leakage.

4) The native method may access a large object, so a local reference to the object is created. The native method performs additional calculations in addition to accessing the object before returning the caller. A local reference to this large object will contain the object to prevent it from being garbage collected. This phenomenon will continue until the native method returns to the caller. Even if the object is no longer used, it will still be protected. In the following example, because deletelocalref is explicitly called before lengthycomputation (), the garbage collector has the opportunity to release the object pointed to by lref.

The essence of this situation is to allow the program to recycle objects that are not accessed by the native code during the execution of the native method.

I don't know how to manage local references. Java 7 should be more powerful. If you have time, go and have a look. Here, follow the characteristics of Java 2. SDK1. 2 provides a set of additional functions to manage the life cycle of local references. They are ensurelocalcapacity, newlocalref, pushlocalfram and poplocalfram. The JNI specification requires that the VM can automatically ensure that each native method can create at least 16 local references. Experience shows that if the native method does not include complex interoperation with Java VM objects, this capacity is sufficient for most native methods. If this is not enough and more local references need to be created, the native method can call ensureleocalcapacity to ensure that these local references have enough space.

In addition, the pushlocalfram \ poplocalfram function allows programmers to create local references to nested scopes. The following code:

Pushlocalfram creates a new scope for the specified number of local references. Poplocalfram destroys the top-level scope and releases all local references in the scope.

The advantage of using these two functions is that they can manage the life cycle of local references without having to relate each individual local reference that may be created during execution. In the example, if the process of processing jstr creates additional local references, they will also be released immediately after poplocalfram.

The newlocalref function is very useful when you write a tool function. This will be analyzed in the following chapter - Rules for managing references.

The native code may create more than 16 local references, or save them in pushlocalfram or ensurelocalcapacity calls. The VM will allocate the required memory for the local references. However, there is no guarantee that these memories are sufficient. If the memory allocation fails, the virtual machine will exit.

Release global reference

When the native code no longer needs to access a global reference, it should call deleteglobalref to release it. If the call to this function fails, the Java VM will not recycle the corresponding object.

When the native code no longer needs to access a weak global reference, it should call deleteweakglobalref to release it. If calling this function fails, the Java VM will still recycle the corresponding underlying object, but will not recycle the memory consumed by the weak reference itself.

Rules for managing references the purpose of managing references is to clear unnecessary memory occupation and object retention.

Generally speaking, there are only two types of native code: functions that directly implement native methods and tool functions used in binary context.

When writing the implementation of the native method, you should be careful of over creating local references in the loop and local references created in the native method but not returned to the caller. After the native method returns, there are still 16 local references in use. It is acceptable to give them to the Java VM for release. However, the call of native methods should not cause the accumulation of global references and weak global references. These references should not be automatically released after the native method returns.

When writing a tool function, you must be careful not to disclose any local reference or execution beyond the function. Because a tool function may be repeatedly called in an unexpected context. Any unnecessary reference creation may lead to memory leakage. 1) When a tool function that returns a base type is called, it must have no local reference, if the global reference is accumulated. 2) When a tool function that returns a reference type is called, it must have no accumulation of local, global or global references, except for the reference to be used as the return value.

A utility function creates some global or weak global references for capture purposes, which is acceptable because these references are created only at the beginning.

If a tool function returns a reference, You should make the type of reference returned (for example, local reference, global reference) as part of the function specification. It should be consistent, rather than sometimes returning a local reference and sometimes returning a global reference. The caller needs to know the type of reference returned by the tool function in order to correctly manage his own JNI reference. The following code repeatedly calls a tool function (getinfostring). We need to know the type of reference returned by getinfostring in order to release the reference:

In Java2 sdk1 2. The newlocalref function can be used to ensure that a tool function always returns a local reference. To illustrate this problem, we make some changes to mynewstring, which caches a frequently requested string ("commonstring") to the global reference:

jstring

Local references are used when the normal process returns. As explained previously, we must save the cached characters to a global reference, so that we can access the native method in multiple threads.

This statement creates a local reference that points to the unified object cached in the global reference. As part of the convention with the caller, mynewstring always returns a local reference.

Pushlocalfram and poplocalfram functions are particularly convenient for managing the life cycle of local references. You only need to call pushlocalfram at the entry of the native function, and call poplocalfram when the function exits, and the local variables will be released.

When the poplocalfram function call fails, it may cause undefined behavior, such as VM crash.

Memory leak problem: the memory leak Java objects of Java heap are stored in Java heap in JVM process space, and Java heap can change dynamically during JVM operation. If more and more Java objects occupy more and more space in Java heap, the JVM will expand the capacity of Java heap at runtime. If the capacity of Java heap is expanded to the maximum and there is still not enough space to allocate new Java objects after GC, an out of memory exception will be thrown, resulting in the collapse of the JVM process. There are two reasons for the out of memory exception in Java heap - ① the program is too large, resulting in too many Java objects at the same time; ② Java heap memory leaks due to programming errors. Java heap memory leaks can occur for a variety of reasons. JNI programming errors can also lead to memory leaks in Java heap. Memory leakage of native memory in JVM from the perspective of operating system, JVM is not fundamentally different from other processes at runtime. At the system level, they have the same scheduling mechanism, the same memory allocation method and the same memory pattern. In the JVM process space, the memory space other than Java heap is called the JVM's native memory. Many resources of a process are stored in the JVM's native memory, such as loaded code images, thread stacks, thread management control blocks, JVM static data, global data, and so on. It also includes the resources allocated by the native code in the JNI program. During JVM operation, most process resources are dynamically allocated from native memory. When more and more resources are allocated in native memory, occupying more and more native memory space and reaching the upper limit of native memory, the JVM will throw an exception to make the JVM process exit abnormally. At this time, Java heap often does not reach the upper limit. The JVM's native memory may leak for a variety of reasons. For example, too many threads are created while the JVM is running and running at the same time. The resources allocated by the JVM to threads may deplete the capacity of native memory. JNI programming errors may also lead to memory leakage of native memory. The discussion on this topic is the focus of this paper.

JNI programming realizes the interaction between native code and Java program. Therefore, JNI code programming not only follows the programming rules of native code programming language, but also abides by the document specifications of JNI programming. In terms of memory management, the memory management mechanism of native code programming language itself should still be followed, and the memory management of JNI programming should also be considered. This chapter briefly summarizes the obvious memory leaks in JNI programming. This paper expounds the memory management of native code programming language and the additional memory management of JNI specification. Memory leakage of native code. JNI programming is first a specific programming language, or C language, or C + +, or assembly, or other native programming languages. Each programming language environment implements its own memory management mechanism. Therefore, JNI program developers should follow the memory management mechanism of native language to avoid memory leakage. Taking C language as an example, when malloc () is used to dynamically allocate memory in the process heap, JNI program should call free () to release memory after using it. In short, all memory leakage rules that should be paid attention to in native language programming are still applicable in JNI programming. The memory leak introduced by the native language itself will cause the memory of native memory. In severe cases, it will cause the out of memory of native memory. The memory leakage JNI programming introduced by global reference also follows JNI specifications and standards. The JVM adds a unique memory management mechanism for JNI programming. The local reference in JNI only exists when the native method is executed, and will automatically become invalid after the native method is executed. This automatic invalidation makes the use of local reference relatively simple. After the execution of native methods, the reference count of the Java objects they reference will be reduced by 1. It will not cause memory leakage of Java objects in Java heap. The reference of global references to Java objects is always valid, so the Java objects they reference will always exist in Java heap. Programmers need to carefully maintain the use of global reference when using global reference. If you must use global reference, be sure to delete it when not in use. Just like in C, after calling malloc () to allocate a memory dynamically, calling free () is released. Otherwise, the Java object referenced by the global reference will stay in the Java heap forever, resulting in memory leakage of the Java heap.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>