JAVA memory leak

Memory management in Java

To understand memory leaks in Java, you must first know how memory in Java is managed.

In Java programs, we usually use new to allocate memory for objects, and these memory spaces are on the heap.

Java determines whether objects can be recycled, but accessibility analysis algorithm.

The basic idea of this algorithm is to use a series of objects named "GC roots" as the starting point to start the downward search from these nodes. The search path is called reference chain. When an object is not connected to GC roots by any reference chain, it is proved that the object is unavailable. Although objects object5, object6 and object7 in the following figure judge each other, However, they are not reachable to GC roots, so they will be determined as recyclable objects.

In the Java language, the objects that can be used as GC roots include the following:

What is a memory leak in Java

Memory leakage in Java, broadly and popularly, is that the memory of objects that will no longer be used can not be recycled, that is, memory leakage.

Memory leaks in Java behave differently than in C + +.

In C + +, all objects allocated memory must be released manually by the programmer after they are no longer used. However, in Java, we don't have to release memory by ourselves. Useless memory is automatically cleaned up by GC, which also greatly simplifies our programming work. But in fact, sometimes some objects that will no longer be used can not be released in the view of GC, which will cause memory leakage.

Objects have a life cycle, some long and some short. If long-lived objects hold short-lived references, memory leaks are likely to occur. For example:

public class Test {
	Object object;
	public void method() {
		object = new Object();
		// ...
	}
}

In fact, we expect the object instance here to only act on the method () method, and it will not be used elsewhere. However, after the method () method is executed, the memory allocated by the object object object will not be considered as an object that can be released immediately. Only after the object created by the test class is released will it be released. Strictly speaking, this is a memory leak. The solution is to use object as a local variable in the method () method. Of course, you can also set the object to null after using it.

public class Test {
	Object object;
	public void method() {
		object = new Object();
		// ...
		object = null;
	}
}

In this way, the memory previously allocated by new object() can be recycled by GC.

Examples of memory leaks in Java

Such as HashMap, LinkedList, etc. If these containers are static, their life cycle is consistent with the program, and the objects in the container will not be released before the end of the program, resulting in memory leakage. In short, long-lived objects hold references to short-lived objects. Although short-lived objects are no longer used, they cannot be recycled because long-lived objects hold their references.

static Vector v = new Vector(); 
for (int i = 1; i<100; i++) 
{ 
    Object o = new Object(); 
    v.add(o); 
    o = null; 
}

In this example, the reference V of the vector object and the reference o of the object object exist in the code stack. In the for loop, we constantly generate new objects, add them to the vector object, and then empty the o reference. The question is whether the object object we created can be recycled by GC if GC occurs after the o reference is empty? The answer is No. Because when GC tracks the references in the code stack, it will find the V reference. If it continues to track down, it will find that there is a reference to the object object in the memory space pointed to by the V reference. That is, although the o reference has been set to null, there are still other references to the object object that can be accessed, so GC cannot release them. If the object object has no effect on the program after this loop, we think that the Java program has a memory leak.

In the process of operating the database, you first need to establish a connection with the database. When it is no longer used, you need to call the close method to release the connection with the database. Only after the connection is closed will the garbage collector recycle the corresponding object. Otherwise, if the connection, statement or resultset is not explicitly closed during database access, a large number of objects will not be recycled, resulting in memory leakage.

Generally speaking, the scope of a variable definition is larger than its use scope, which is likely to cause memory leakage. On the other hand, if the object is not set to null in time, it is likely to lead to memory leakage.

public class UsingRandom {
	private String msg;
	public void receiveMsg(){	
		readFromNet();// 从网络中接受数据保存到msg中
		saveDB();// 把msg保存到数据库中
	}
}

If this pseudo code is stored in the variable MSG by the readFromNet () method, then the saveDB () method is used to save the contents of MSG to the database. At this time, MSG is useless. Because the life cycle of MSG is the same as the life cycle of the object, MSG can not be recovered at the same time, resulting in memory leakage.

In fact, this msg variable can be placed inside the receivemsg () method. When the method is used up, the MSG life cycle will end and can be recycled. Another method is to set msg to null after using MSG, so that the garbage collector will also recycle the memory space of MSG.

If the method of an instance object of an external class returns an instance object of an internal class, the internal class object has been referenced for a long time. Even if the external class instance object is no longer used, because the internal class holds the instance object of the external class, the external class object will not be garbage collected, which will also cause memory leakage.

After an object is stored in the HashSet set, you cannot modify the fields in the object that participate in the calculation of hash value. Otherwise, the hash value of the object after modification is different from the hash value originally stored in the HashSet set. In this case, Even if the contains method uses the current reference of the object as a parameter to retrieve the object in the HashSet collection, it will return the result that the object cannot be found, which will lead to the failure to delete the current object separately from the HashSet collection, resulting in memory leakage.

public static void main(String[] args) 
{ 
    Set<Person> set = new HashSet<Person>(); 
    Person p1 = new Person("唐僧","pwd1",25); 
    Person p2 = new Person("孙悟空","pwd2",26); 
    Person p3 = new Person("猪八戒","pwd3",27); 
    set.add(p1); 
    set.add(p2); 
    set.add(p3); 
    System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:3 个元素! 
    p3.setAge(2); //修改p3的年龄,此时p3元素对应的hashcode值发生改变 
    set.remove(p3); //此时remove不掉,造成内存泄漏
    set.add(p3); //重新添加,居然添加成功 
    System.out.println("总共有:"+set.size()+" 个元素!"); //结果:总共有:4 个元素! 
    for (Person person : set) 
    { 
        System.out.println(person); 
    } 
}

Another common source of memory leakage is the cache. Once you put an object reference into the cache, it is easy to forget. For this problem, you can use weakhashmap to represent the cache. The feature of this map is that when the key has no other reference except its own reference to the key, the map will automatically discard this value

The third common source of memory leaks is listeners and other callbacks. If the client registers callbacks in the API you implement, but does not display cancellations, it will accumulate. The best way to ensure that callbacks are immediately garbage collected is to save only their weak references, for example, as keys in the weakhashmap.

Principles for solving memory leaks

1. Minimize the use of static variables, the life cycle of static variables of classes and the synchronization of classes.

2. Before declaring the object reference, specify the effective scope of the memory object, minimize the scope of the object, and rewrite the member variable of the class into a local variable in the method;

3. Reduce the number of objects with long life cycle holding references with short life cycle;

4. Use StringBuilder and StringBuffer to connect strings. Sting, StringBuilder and StringBuffer can represent strings. String strings represent immutable strings, and the latter two represent variable strings. If multiple string objects are used for string connection operation, a large number of temporary strings may be generated at run time, which will be saved in memory, resulting in program performance degradation.

5. Manually set null value for objects that do not need to be used. No matter when GC starts cleaning, we should timely mark useless objects as objects that can be cleaned;

6. For various connection (database connection, network connection, IO connection) operations, be sure to call close to close.

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
分享
二维码
< <上一篇
下一篇>>