How can I create a memory leak in Java?

后端 未结 30 1807
没有蜡笔的小新
没有蜡笔的小新 2020-11-21 22:26

I just had an interview, and I was asked to create a memory leak with Java.

Needless to say, I felt pretty dumb having no clue on how to eve

30条回答
  •  旧时难觅i
    2020-11-21 22:43

    I came across a more subtle kind of resource leak recently. We open resources via class loader's getResourceAsStream and it happened that the input stream handles were not closed.

    Uhm, you might say, what an idiot.

    Well, what makes this interesting is: this way, you can leak heap memory of the underlying process, rather than from JVM's heap.

    All you need is a jar file with a file inside which will be referenced from Java code. The bigger the jar file, the quicker memory gets allocated.

    You can easily create such a jar with the following class:

    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipOutputStream;
    
    public class BigJarCreator {
        public static void main(String[] args) throws IOException {
            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(new File("big.jar")));
            zos.putNextEntry(new ZipEntry("resource.txt"));
            zos.write("not too much in here".getBytes());
            zos.closeEntry();
            zos.putNextEntry(new ZipEntry("largeFile.out"));
            for (int i=0 ; i<10000000 ; i++) {
                zos.write((int) (Math.round(Math.random()*100)+20));
            }
            zos.closeEntry();
            zos.close();
        }
    }
    

    Just paste into a file named BigJarCreator.java, compile and run it from command line:

    javac BigJarCreator.java
    java -cp . BigJarCreator
    

    Et voilà: you find a jar archive in your current working directory with two files inside.

    Let's create a second class:

    public class MemLeak {
        public static void main(String[] args) throws InterruptedException {
            int ITERATIONS=100000;
            for (int i=0 ; i

    This class basically does nothing, but create unreferenced InputStream objects. Those objects will be garbage collected immediately and thus, do not contribute to heap size. It is important for our example to load an existing resource from a jar file, and size does matter here!

    If you're doubtful, try to compile and start the class above, but make sure to chose a decent heap size (2 MB):

    javac MemLeak.java
    java -Xmx2m -classpath .:big.jar MemLeak
    

    You will not encounter an OOM error here, as no references are kept, the application will keep running no matter how large you chose ITERATIONS in the above example. The memory consumption of your process (visible in top (RES/RSS) or process explorer) grows unless the application gets to the wait command. In the setup above, it will allocate around 150 MB in memory.

    If you want the application to play safe, close the input stream right where it's created:

    MemLeak.class.getClassLoader().getResourceAsStream("resource.txt").close();
    

    and your process will not exceed 35 MB, independent of the iteration count.

    Quite simple and surprising.

提交回复
热议问题