Java String Memory Leak

By : Avinash
Source: Stackoverflow.com
Question!

I am not java expert.

My code is reading a file into a String. This code gets executed every 5 minutes. The size of file varies. Sometimes it is 100 sometimes it is 1000 lines.

I am experience Out Of Memory, after some days.

The question I have is, when my codes goes out of scope of the Reading file function, does Java garbage collect the String?

I am pretty confused by reading on the internet. Some people says it does not get deleted and use StringBuffer.

// Demonstrate FileReader.

import java.io.*;
class FileReaderDemo {
    public static void read(BufferedReader br) throws Exception {
        long length = 0;
        String s;
        while (true) {
            s = br.readLine();
            s += "abcd";
            if (s == null) {
                break;
            }
            length += s.length();
            //System.out.println(s);
        }
        System.out.println("Read: " + (length / 1024 / 1024) + " MB");
    }

    public static void main(String args[]) throws Exception {
        //FileReader fr = new FileReader("FileReaderDemo.java");
        FileReader fr = new FileReader("big_file.txt.1");
        BufferedReader br = new BufferedReader(fr);
        String s;
        read(br);
        fr = new FileReader("big_file.txt.1");
        br = new BufferedReader(fr);
        read(br);
        fr = new FileReader("big_file.txt.1");
        br = new BufferedReader(fr);
        read(br);
        fr = new FileReader("big_file.txt.1");
        br = new BufferedReader(fr);
        read(br);
        BufferedReader in = new BufferedReader(new InputStreamReader(System. in )); in .readLine();
        fr.close();
    }
}
By : Avinash


Answers

As pointed out by others this code never terminates. It looks like the code you posted is not the original code you are having problems with.

Hard to diagnose without seeing the actual code, but Strings will definitely be garbage collected once they are not referenced from other parts of the code.

Wild guess: Are you calling close() on your Readers and InputStreams once you're done with them? If not, this could be the cause of your out of memory errors.



change the program like below to consume less memory. A huge source of memory consumption is due to your repeated string concatenation of s = "abcd"; - avoid that and you'll probably more than halve your memory consumption (not tested - profile it yourself if you want to know).

public static void read(BufferedReader br) throws Exception {

    long length = 0;
    //String s; 
By : Chii


The code that you have posted won't leak memory. However, the while (true) loop will never terminate because s will never be null at the point that you test it.


Lets change it a bit to make it "work"

    public static void read(BufferedReader br) throws Exception {
            long length = 0;
            String s = "";
            while (true) {
                    String ss = br.readLine();
                    if (ss == null) {
                            break;
                    }
                    s  = ss;
                    length  = ss.length();
            }
            System.out.println("Read: "   (length/1024/1024)   " MB");
    }

This code doesn't leak memory either because the Strings created in the method will all be candidates for garbage collection when the method returns (if not before).

Each time we execute s = ss; a new string is created consisting of all of the characters currently in s and the characters in ss. Assuming there are N lines containing an average of L characters, the s = ss; statement will be called N times, will create N strings, and will copy on average (N * L)^2 / 2 characters.


However, there is a good reason to make a StringBuilder and that is to reduce the amount of String allocation and character copying that goes on. Lets rewrite the method to use a StringBuilder; i.e. a replacement for StringBuffer that is not synchronized.

    public static void read(BufferedReader br) throws Exception {
            long length = 0;
            StringBuilder sb = new StringBuilder(sb);
            while (true) {
                    String ss = br.readLine();
                    if (ss == null) {
                            break;
                    }
                    sb.append(ss);
                    length  = ss.length();
            }
            System.out.println("Read: "   (length/1024/1024)   " MB");
    }

This version will reallocate the StringBuilder's internal character array at most log2(N) times and copy at most 2 * N * L characters.


Summary - using the StringBuilder is a good idea, but not because of memory leaks. If you have a memory leak, it is not in the original sample code or in the fixed version.

By : Stephen C


This video can help you solving your question :)
By: admin