Home > Java > javaTutorial > How to write a piece of code in java to cause a memory leak

How to write a piece of code in java to cause a memory leak

伊谢尔伦
Release: 2016-11-25 10:42:13
Original
1547 people have browsed it

The text comes from a popular discussion on the StackOverflow Q&A website: How to write a piece of code in Java that will cause memory leaks.

  Q: I just participated in an interview, and the interviewer asked me how to write Java code that causes memory leaks. I have no idea about this question, which is so embarrassing.

 A1: Memory leaks can easily occur through the following steps (program code cannot access certain objects, but they are still saved in memory):

The application creates a long-running thread (or uses a thread pool, which will memory leaks occur faster).

The thread loads a class through a certain class loader (can be customized).

This class allocates a large block of memory (such as new byte[1000000]), stores a strong reference in a static variable, and then stores its own reference in ThreadLocal. Allocating additional memory new byte[1000000] is optional (class instance leaks are sufficient), but this will make the memory leak faster.

Threads clean up custom classes or the class loader that loads the class.

Repeat the above steps.

Since there is no reference to the class and class loader, the storage in ThreadLocal cannot be accessed. ThreadLocal holds a reference to the object, and it also holds a reference to the class and its class loader. The class loader holds all references to the classes it loads, so that the GC cannot reclaim the memory stored in ThreadLocal. In many JVM implementations, Java classes and class loaders are directly allocated to the permgen area without performing GC, which leads to more serious memory leaks.

One of the variants of this leak pattern is that if you frequently redeploy applications and application containers (such as Tomcat) that use ThreadLocal in any form, memory leaks will easily occur (because the application container uses threads as mentioned above , a new classloader will be used each time the app is redeployed).

 A2:

 Static variable reference object

class MemorableClass {
    static final ArrayList list = new ArrayList(100);
}
Copy after login

Call String.intern() of a long string

String str=readString(); // read lengthy string any source db,textbox/jsp etc..
// This will place the string in memory pool from which you cant remove
str.intern();
Copy after login

Opened streams (files, networks, etc.) are not closed

try {
    BufferedReader br = new BufferedReader(new FileReader(inputFile));
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}
Copy after login

The connection is not closed

try {
    Connection conn = ConnectionFactory.getConnection();
    ...
    ...
} catch (Exception e) {
    e.printStacktrace();
}
Copy after login

JVM’s GC is not available Reach area

 For example, memory allocated through native method.

  Objects of the web application in the application scope, the application has not been restarted or not explicitly removed

  getServletContext().setAttribute("SOME_MAP", map);

  Objects of the web application in the session scope, have not been invalidated or have not been explicitly removed Remove

 session.setAttribute("SOME_MAP", map);

 Incorrect or inappropriate JVM options

 For example, IBM JDK's noclassgc prevents garbage collection of useless classes

 A3: If HashSet is not implemented correctly (or Not implemented) hashCode() or equals() will cause "copies" to continue to be added to the collection. If the collection fails to ignore the elements it should ignore, its size can only continue to grow, and the elements cannot be deleted.

 If you want to generate wrong key-value pairs, you can do as follows:

class BadKey {
   // no hashCode or equals();
   public final String key;
   public BadKey(String key) { this.key = key; }
}
  
Map map = System.getProperties();
map.put(new BadKey("key"), "value"); // Memory leak even if your threads die.
Copy after login

A4: In addition to forgotten listeners, static references, key errors/modifications in the hashmap or thread blocking that cannot end the life cycle, etc. Memory leak scenarios, here are some less obvious Java memory leak scenarios, mainly related to threads.

Runtime.addShutdownHook is not removed. Even if removeShutdownHook is used, due to the bug of the ThreadGroup class for unstarted threads, it may not be recycled, causing a memory leak in the ThreadGroup.

Threads are created but not started, the same situation as above

Creating threads that inherit ContextClassLoader and AccessControlContext, the use of ThreadGroup and InheritedThreadLocal, all these references are potential leaks, as well as all classes loaded by the class loader and all Static references and so on. This has a very obvious impact on the ThreadFactory interface as an important component of the entire j.u.c.Executor framework (java.util.concurrent), and many developers have not noticed its potential dangers. And many libraries will start threads according to requests.

ThreadLocal caching is not a good practice in many cases. There are many implementations of simple caching based on ThreadLocal, but the ContextClassLoader will leak if the thread continues to run outside its expected life cycle. Don't use ThreadLocal caching unless really necessary.

ThreadGroup.destroy() is called when ThreadGroup itself has no threads but still has child thread groups. If a memory leak occurs, the thread group cannot be removed from its parent thread group and child thread groups cannot be enumerated.

Using WeakHashMap, value directly (indirectly) refers to key, which is a difficult situation to find. This also applies if a class inheriting Weak/SoftReference may hold a strong reference to the protected object.

Use java.net.URL of http(s) protocol to download resources. KeepAliveCache creates a new thread in the system ThreadGroup, causing the context class loader memory of the current thread to leak. The thread is created on the first request when there is no surviving thread, so a leak is very likely to occur. (This has been fixed in Java 7, the code that creates the thread properly removes the context class loader.)

Use InflaterInputStream to pass new java.util.zip.Inflater() in the constructor (such as PNGImageDecoder) and do not call the end() of the inflater. Just new is very safe, but if you create the class yourself as a constructor parameter and call the close() of the stream and cannot close the inflater, memory leaks may occur. This is not really a memory leak because it will be released by the finalizer. But this consumes a lot of native memory, causing Linux's oom_killer to kill the process. So the lesson this teaches us is: release native resources as early as possible.

The same goes for java.util.zip.Deflater, which is even more serious. The good thing may be that Deflater is rarely used. If you create a Deflater or Inflater yourself, remember that you must call end().


Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template