How to avoid java program memory leak

Although jvm has a garbage collection mechanism, if the program is written without paying attention to certain specific rules, it will still cause a memory leak in the java program, and an OutOfMemory exception may eventually occur.

1. Causes of Java memory leaks

Objects in java are divided into two types in terms of use, referenced and unreferenced. Garbage collection will only reclaim unreferenced objects. The referenced object, even if it is no longer used, will not be recycled. Therefore, if there are a large number of referenced useless objects in the program, there is a memory leak.

2.java heap memory (Heap) leak

The size of the jvm heap memory is specified by two parameters -Xms and -Xmx.

2.1 Objects are referenced by static members

When a large object is referenced by a static member, it will cause a memory leak.

Example:

private Random random = new Random();

public static final ArrayList<Double> list = new ArrayList<Double>(1000000);

for (int i = 0; i < 1000000; i++) { list.add(random.nextDouble()); }

ArrayList is an object dynamically allocated on the heap. Under normal circumstances, it will be recycled by gc after it is used up. However, in this example, because it is referenced by the static member list, and the static member will not be recycled, it will cause this problem very quickly. Large ArrayLists stay in heap memory all the time.

Therefore, you need to pay special attention to the use of static members, and avoid static members referring to large objects or objects of collection type (such as ArrayList, etc.).

2.2 String's intern method

Call the String.intern() method on a large string, intern() will put the String in the jvm memory pool (PermGen), and the jvm memory pool will not be gc. Therefore, if the intern() method is called for a large string, a large amount of memory that cannot be gc will be generated, resulting in a memory leak.

If you must use the intern method of a large string, you should adjust the size of the PermGen memory through the -XX:MaxPermSize parameter.

2.3 The stream is not closed after reading

Often times during development we forget to close streams, which can lead to memory leaks. Because each stream corresponds to an open file handle at the operating system level, if the stream is not closed, the file handle of the operating system will always be open, and jvm will consume memory to track the file handle opened by the operating system.
Example:

BufferedReader br = new BufferedReader(new FileReader(path));
return br.readLine();

To solve this problem, in versions prior to java8, you can add a closing operation to finally:

 BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        if (br != null) br.close();
    }

The try-with-resources statement can be used in java8:

try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
}

For network connections and database connections, etc., attention should also be paid to the closing of connections. If a connection pool is used, the closing operation is responsible for the connection pool, and there is no need to deal with it in the program.

2.4 Add objects that do not implement the hashCode() and equals() methods to the HashSet

This is a simple but common scenario. Under normal circumstances, Set will filter duplicate objects, but if there is no implementation of hashCode() and equals(), duplicate objects will continue to be added to Set, and there will be no chance to remove them.

Therefore, it is a good programming practice to add the implementation of hashCode() and equals() methods to the class. This function can be easily realized through Lombok's @EqualsAndHashCode.

3. How to find memory leaks

3.1 record gc log

By specifying -verbose:gc in the jvm parameter, you can record the details of each gc to analyze the use of memory.

3.2 Profiling

Perform memory analysis through Visual VM or Java Mission Control that comes with jdk.

3.3 Code Review

Through code review and static code inspection, find wrong code that causes memory leak issues.

4. Summary

Code-level inspection can help find some memory leaks, but memory leaks in the production environment are often not easy to find in advance, because many problems only appear in large concurrency scenarios. Therefore, it is also necessary to conduct stress testing through stress testing tools to discover potential memory leaks in advance.

Guess you like

Origin blog.csdn.net/haiyan_qi/article/details/79179852