Wednesday, November 21, 2018

Memory Leak in Java

Memory Leak Creation in Java

Memory leak happens when memory can't be claimed by GC as some areas are unreachable from JVM's garbage collector, 
such as memory allocated through native methods. It gets worse over time. Below are samples of memory leak creation.

1) Create Static field holding object reference esp final fields.
    class MemorableClass {
        static final ArrayList list = new ArrayList(100);
    }

2) Calling String.intern() on lengthy String.
    String str=readString(); //Read lengthy string any source db,textbox/jsp etc..
    str.intern(); //This will place the string in memory pool from which you can't remove.
    
    Ex:
    public class StringLeaker {
        private final String smallString;
        public StringLeaker() {
            String veryLongString = "We hold these truths to be self-evident...";
            this.smallString = veryLongString.substring(0, 1); //The substring maintains a reference to internal char[] representation of the original string.
        }
    }
    Because the substring refers to the internal representation of the original, very long string, the original stays in memory. 
    Thus, as long as you have a StringLeaker in play, you have the whole original string in memory. 
    
    Worse:
    this.smallString = veryLongString.substring(0, 1).intern(); //Both will be in memory even after Class is discarded.
    
    Want to avoid this, use this:
        this.smallString = new String(veryLongString.substring(0, 1));
        
3) Unclosed open streams (file, network etc...)
    try {
        BufferedReader br = new BufferedReader(new FileReader(inputFile));
        ...
        ...
    } catch (Exception e) {
        e.printStacktrace();
    }
    
    AND
    
    public class Main {
        public static void main(String args[]) {
            Socket s = new Socket(InetAddress.getByName("google.com"),80);
            s=null; //at this point, because you didn't close the socket properly, you have a leak of a native descriptor, which uses memory. 
        }
    }

4) Unclosed connections. However Closeable is introduced recently.
    try {
        Connection conn = ConnectionFactory.getConnection();
        ...
        ...
    } catch (Exception e) {
        e.printStacktrace();
    }
    
5) Incorrect or inappropriate JVM options, such as the "noclassgc" option prevents unused class garbage collection.

6) Creating, but not starting, a Thread. Creating a thread inherits the ContextClassLoader and AccessControlContext, 
   plus the ThreadGroup and any InheritedThreadLocal, all those references are potential leaks, along with the entire class 
   loaded by the classloader and all static references. Such threads get added to ThreadGroup. It increases the unstarted 
   thread count, also ThreadGroup can't destroy unstarted threads. 
   
7) Calling ThreadGroup.destroy() when the ThreadGroup has no threads itself, but it still keeps child ThreadGroups. 
   A bad leak that will prevent the ThreadGroup to remove from its parent.

8) Keep growing a Queue, without clearing...