This article describes in detail the principles of Java memory management, as well as the causes of memory leaks, and provides a number of solutions to solve Java memory leaks, in the hope that Java developers have some help.
Java Memory Management mechanism
In the C + + language, if you need to allocate a chunk of memory dynamically, programmers need to be responsible for the entire life cycle of this memory. From the application assignment, to the use, to the final release. The process is very flexible, but cumbersome, and the programmer is prone to inadvertently forget to release memory, resulting in memory leaks. The Java language has made its own optimizations for memory management, which is the garbage collection mechanism. Almost all memory objects in Java are allocated on heap memory (except for the base data type), and the GC (garbage collection) is responsible for automatically reclaiming memory that is no longer in use.
Above is the basic situation of the Java Memory management mechanism. But if we just understand this, we will still encounter memory leaks in the actual project development. Perhaps some people doubt that, since the Java garbage collection mechanism can automatically reclaim memory, how can there be a memory leak situation? This problem, we need to know when the GC reclaims memory objects, what kind of memory objects will be considered by the GC is "no longer used".
Access to memory objects in Java, using a reference method. In Java code we maintain a reference variable of a memory object, and through the value of the reference variable, we can access the memory object space in the corresponding memory address. In a Java program, the reference variable itself can be stored in heap memory and placed in the memory of the code stack (the same as the basic data type). GC threads start tracking from reference variables in the code stack to determine which memory is being used. If the GC thread is unable to trace a chunk of memory in this way, then the GC will assume that the memory is no longer in use (because the memory is inaccessible in the code).
With this graph-based approach to memory management, a GC can recycle a memory object after it loses all references. Conversely, if the object still has a reference, it will not be recycled by GC, even if the Java virtual machine throws OutOfMemoryError.
Java memory leaks Generally, there are two cases of a memory leak. A situation such as in the C + + language, the allocated memory in the heap, when it is not released, all the way to access the memory is deleted (such as pointer re-assignment), and the other is that the memory object is clearly not needed, still retains the memory and its access (reference). The first case, in Java has been due to the introduction of garbage collection mechanism, has been well resolved. So, the memory leak in Java, mainly refers to the second case.
Perhaps the concept of light is too abstract, you can look at this example:
Vector v = new vector (ten); for (int i = 1; i <, i + +) { object o = New object (); V.add (o); o = null; }
In this example, there is a reference to the vector object in the code stack with reference to the V and object o. In the For loop, we constantly generate new objects, add them to the Vector object, and then empty the O reference. The question is, if a GC occurs when the O reference is empty, can we create an object that is recycled by GC? The answer is in the negative. Because, when the GC traces a reference in the code stack, it discovers a V reference, and continues to trace, it finds that the memory space pointed to by the V reference has a reference to the object. This means that although the O reference is already empty, there are still other references to object objects that can be accessed, so the GC cannot release it. If after this loop the object object has no effect on the program, we assume that the Java program has a memory leak.
Despite the small amount of damage caused by a Java memory leak in the case of memory leaks in C + +, in most cases the program will still run normally, except in the rare case of a program crash. However, when mobile devices have tighter limits on both memory and CPU, Java's memory overflow can lead to inefficient programs and high memory consumption. This results in a poor performance of the entire machine, which can also cause the outofmemoryerror to be thrown, causing the program to crash.
Avoidance of memory leaks under normal circumstances
In general cases where complex data structures are not involved, Java's memory leaks behave as a memory object whose lifetime exceeds the length of time the program needs it. We also sometimes call it "object Free".
For example:
public class filesearch{ private byte [] content; Private File mfile; Public filesearch (file file) { mfile = file; } public boolean hasstring (String str) { int size = GetFileSize (mfile); Content = new byte [size]; LoadFile (mfile, content); string s = new string (content); return S.contains (str); } }
In this code, there is a function hasstring in the FileSearch class to determine whether the document contains the specified string. The process is to load the mfile into memory first and then make a judgment. However, the problem here is that the content is declared in order to be an instance variable, not a local variable. Then, after this function returns, there is still data for the entire file in memory. It is clear that the data we follow is no longer needed, which creates an unwarranted waste of memory.
To avoid a memory leak in this case, we need to manage our own allocated memory in C + + memory management thinking. The first is to clarify the valid scope of the memory object before declaring the object reference. A memory object that is valid within a function should be declared as a local variable, the same as the life cycle of the class instance, to be declared as an instance variable ... And so on Second, when the memory object is no longer needed, remember to manually empty its reference.
Memory leak problems in complex data structures
In actual projects, we often use some more complex data structures to cache the information needed for the program to run. Sometimes, because the data structure is too complex, or we have some special needs (for example, in case of memory permitting, as much as possible to cache information to improve the speed of the program, etc.), it is difficult for us to define the life cycle of data structure. At this point, we can use a special mechanism in Java to prevent memory leaks.
As we have described before, the GC mechanism of Java is built on the reference mechanism for tracking memory. And before that, the references we used all just defined an "Object o; "In such a form." In fact, this is just one of the default cases in the Java reference mechanism, and there are other ways to refer to it. By using these special reference mechanisms, together with the GC mechanism, we can achieve some of the effects we need.
Several ways of referencing in Java
There are several different ways of referencing in Java: Strong, soft, weak, and virtual. Below, we begin with a detailed understanding of the implications of these kinds of citation methods.
Strong references
The references we used earlier in this article were strong references, which are the most common references. If an object has a strong reference, it is similar to essential necessities, and the garbage collector will never recycle it. When there is not enough memory space, the Java virtual machine prefers to throw a outofmemoryerror error, which causes the program to terminate abnormally, and does not rely on random recycling of strongly referenced objects to resolve out-of-memory issues.
Soft references (SoftReference)
A typical use of the SoftReference class is for memory-sensitive caches. The principle of softreference is to ensure that all soft references are purged before the JVM reports an out-of-memory condition while maintaining a reference to the object. The key is that the garbage collector may (and may not) release soft-and-accessible objects at run time. Whether an object is disposed depends on the algorithm of the garbage collector and the amount of memory available when the garbage collector is running.
Weak references (WeakReference)
A typical use of the WeakReference class is normalized mapping (canonicalized mapping). In addition, weak references are useful for objects that have a relatively long lifetime and are not expensive to recreate. The key is that when the garbage collector runs, if it encounters a weakly accessible object, the object referenced by WeakReference is freed. Note, however, that the garbage collector may have to run multiple times to find and release a weak and accessible object.
Virtual Reference (Phantomreference)
The
phantomreference class can only be used to track the upcoming collection of referenced objects. Also, it can be used to perform pre-mortem cleanup operations. phantomreference must be used with the referencequeue class. Need referencequeue because it can act as a notification mechanism. When the garbage collector determines that an object is a virtual object, the phantomreference object is placed on its referencequeue . Placing the phantomreference object on referencequeue is also a notification that the object referenced by the phantomreference object has ended, Available for collection. This allows you to take action just before the memory that the object occupies is recycled. Reference is used in conjunction with Referencequeue.
GC, Reference interaction with Referencequeue A, GC cannot delete memory of an object that has a strong reference. B. GC discovers an object memory that has only soft references, then: the referent field of the ①softreference object is set to NULL, so that the object no longer references the heap object. The heap object referenced by ②softreference is declared as finalizable. ③ when the Finalize () method of the heap object is run and the memory occupied by the object is freed, the SoftReference object is added to its referencequeue (if the latter exists). C, GC discovers a weakly referenced object memory, then: the referent field of the ①weakreference object is set to NULL, so that the object no longer references the heap object. The heap object referenced by ②weakreference is declared as finalizable. ③ when the Finalize () method of the heap object is run and the memory occupied by the object is freed, the WeakReference object is added to its referencequeue (if the latter exists). D, GC discovers a virtual reference to the object memory, then: ①phantomreference the referenced heap object is declared as finalizable. ②phantomreference is added to its referencequeue before the heap object is freed. Notable places are the following: 1. In general, GC will not find soft-referenced memory objects, only when the memory is clearly insufficient to discover and release the soft reference object memory. 2, the GC discovery and release of weak references is not immediately, sometimes need to repeat several times GC, only to find and release the weak reference memory objects.
3, soft reference and weak reference when added to Referencequeue, its reference to the real memory has been set to empty, the associated memory has been released. While the virtual reference is added to the Referencequeue, the memory is not released and can still be accessed.
code Example
Through the above introduction, I believe you have the reference mechanism of Java and several references to the similarities and differences already have a certain understanding. The concept of light, which may be too abstract, follows an example of how to use the Reference mechanism in code.
String str = new string ("Hello"); ① Referencequeue < string > RQ = new Referencequeue < String > (); ② WeakReference < string > wf = new WeakReference < String > (str, RQ); ③ str = null; ④ suppress a strong reference to "Hello" Object String str1 = Wf.get (); ⑤ if the "Hello" object is not recycled, str1 references the "Hello" object //If the "Hello" object is not reclaimed, rq.poll () returns null Reference < Extends String > ref = Rq.poll (); ⑥
In the above code, note ⑤⑥ two places. If the "Hello" object is not reclaimed Wf.get () returns a "Hello" string object, Rq.poll () returns NULL, and the "Hello" object has been reclaimed, then wf.get () returns NULL, Rq.poll () returns R The Eference object, but there is no reference to the Str object in this Reference object (Phantomreference is different from WeakReference, SoftReference).
Combined application of reference mechanism and complex data structure
By understanding the GC mechanism, the reference mechanism, and with the referencequeue, we can implement some complex data types that prevent memory overflow.
For example, SoftReference has the trait of building a cache system, so we can implement a simple caching system with a hash table. This ensures that you can cache as much information as possible and that the Java virtual machine does not throw outofmemoryerror because of memory leaks. This caching mechanism is especially suitable for long life cycles of memory objects, and it takes a long time to generate memory objects, such as cache list cover pictures. For some long life cycles, but with little overhead in generating memory objects, using WeakReference can achieve better memory management results.
Attached to the source of Softhashmap, I believe that after watching, we will have a more in-depth understanding of the application of the Reference mechanism.
Package com. * *. widgets; : Softhashmap.java import Java.util. * ; Import Java.lang.ref. * ; Import Android.util.Log; public class Softhashmap extends Abstractmap {/** The internal HashMap that would hold the softreference. */private final MAP hash = new HashMap (); /** the number of "hard" references-to-hold internally. */private final int hard_size; /** the FIFO list of hard references, order of last access. */private final LinkedList Hardcache = new LinkedList (); /** Reference queue for cleared SoftReference objects. */private Referencequeue queue = new Referencequeue (); Strong Reference Number Public softhashmap () {this (100);} Public softhashmap (int hardsize) {hard_size = hardsize;} public object get (object key) {object result = NULL; We Get the SoftreferencE represented by that key softreference Soft_ref = (softreference) hash.get (key); if (soft_ref! = null) {//from the softreference we get the value, which can is//null I F It is not in the map, or it is removed in//the Processqueue () method defined below result = Soft_ref.get (); if (result = = NULL) {//If the value has been garbage collected, remove the//entry From the HashMap. Hash.remove (key); } else {///We Now add this object to the beginning of the hard/reference queue. One reference can occur more than//once, because lookups of the FIFO queue is slow, so// We don ' t want to search through it per time to remove//duplicates. Keep Recent use object in memory Hardcache.addfirst (result); if (hArdcache.size () > Hard_size) {//Remove the last entry if list longer than hard_size Hardcache.removelast (); }}} return result; }/** We define our own subclass of SoftReference which contains not only the value but also the key to Make it easier to find the entry in the HashMap after it ' s been garbage collected. */private static class Softvalue extends SoftReference {private final Object key; Always make data member final/** do you know that a outer class can access private data Membe RS and methods of an inner class? I didn ' t know that! I thought it is only the inner class who could access the outer class ' private information. An outer class can also access private members of a inner class inside its inner class. */Private Softvalue (Object K, ObJect key, Referencequeue q) {super (k, q); this. Key = key; }}/** here we go through the referencequeue and remove garbage collected softvalue objects fro M the HashMap by looking them up using the the Softvalue.key data member. */public void Processqueue () {Softvalue SV; while (SV = (softvalue) queue.poll ()) = null) {if (sv.get () = = null) {LOG.E (" Processqueue "," null "); } else {log.e ("Processqueue", "not NULL"); } hash.remove (Sv.key); We can access private data! LOG.E ("Softhashmap", "release" + Sv.key); }}/** Here we put the key, and value pair into the HASHMAP using a Softvalue object. */public object put (object key, Object value) {Processqueue (); Throw out garbage collected values first LOG.E ("Softhashmap", "put into" + key); Return Hash.put (Key, new Softvalue (value, key, queue)); } public object remove (object key) {Processqueue (); Throw out garbage collected values first return Hash.remove (key); } public void Clear () {hardcache.clear (); Processqueue (); Throw out garbage collected values hash.clear (); } public int size () {processqueue (); Throw out garbage collected values first return hash.size (); } public Set EntrySet () {//No, no, if not!!! Grrr throw new Unsupportedoperationexception (); } }
Understanding and resolution of Java memory leaks