Java字符串内存泄漏

时间:2011-05-20 12:53:32

标签: java memory memory-leaks garbage-collection out-of-memory

我不是java专家。

我的代码正在将文件读入String。此代码每5分钟执行一次。 文件大小各不相同。有时它是100有时它是1000行。

过了几天,我经历了记忆力不足。

我的问题是,当我的代码超出Reading file function的范围时,Java垃圾会收集字符串吗?

我在互联网上阅读时感到非常困惑。有人说它不会被删除并使用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();
    }
}

5 个答案:

答案 0 :(得分:6)

  

你好,我不是java专家。

每个人都有他们可以学到的东西。

  

我的代码正在将文件读入字符串,此代码每5分钟执行一次。现在有时文件大小为100行,有时为1000行。

听起来不是很大或很频繁。应该不是问题。

  

过了几天,我经历了记忆力不足。

您应该能够获得堆转储并查看内存耗尽的原因以及原因。

  

我的问题是,当我的代码超出了阅读文件功能的范围时。 Java Garbage是否收集字符串。

当通过强参考无法再访问时,可以收集它。

  

我很困惑,在互联网上阅读有人说它不会被删除并使用StringBuffer

听起来你来对了地方。我从来没有听过那个。

答案 1 :(得分:5)

您的read方法永远不会终止。到达文件末尾后,您只需继续将字符串"nullabcd"永久添加到s

编辑:忘了,每次重新分配s。但是,我无法看到您的read方法如何终止。

答案 2 :(得分:3)

您发布的代码不会泄漏内存。但是,while (true)循环永远不会终止,因为s在您测试时永远不会是null


让我们稍微改变它以使其“正常”

    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");
    }

此代码不会泄漏内存,因为在方法返回时(如果不是之前),方法中创建的字符串将全部成为垃圾收集的候选者。

每次执行s += ss;时,都会创建一个新字符串,其中包含s中当前所有字符和ss中的字符。假设有N行包含平均L个字符,s += ss;语句将被调用N次,将创建N个字符串,并将复制平均(N * L)^2 / 2个字符。


但是, 是制作StringBuilder的一个很好的理由,那就是减少字符串分配和字符复制的数量。让我们重写方法以使用StringBuilder;即替换未同步的StringBuffer

    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");
    }

此版本最多会重新分配StringBuilder的内部字符数组 log2(N)次,并复制最多 2 * N * L个字符。


总结 - 使用StringBuilder是一个好主意,但不是因为内存泄漏。如果您有内存泄漏,则它不在原始示例代码或固定版本中。

答案 3 :(得分:2)

如下所示更改程序以减少内存消耗。一个巨大的内存消耗来源是由于你重复s += "abcd";的字符串连接 - 避免这种情况,你可能会将你的内存消耗减半(未经测试 - 如果你想知道的话,自己进行配置)。

public static void read(BufferedReader br) throws Exception {

    long length = 0;
    //String s; <--- change to the line below
    StringBuilder sb = new StringBuilder();
    while (true) {
        String s = br.readLine();
        if (s == null) {
            break;
        }
        //s += "abcd";  <--- change to the line below
        sb.append(s).append("abcd");
        length += s.length();
        //System.out.println(s);
    }
    System.out.println("Read: " + (length / 1024 / 1024) + " MB");
}

答案 4 :(得分:1)

正如其他人所指出的,这段代码永远不会终止。看起来您发布的代码不是您遇到问题的原始代码。

很难在没有看到实际代码的情况下进行诊断,但是一旦没有从代码的其他部分引用它们,它们 肯定会被垃圾收集。

狂野猜测:一旦你完成了它们,你是否在你的读者和输入流上调用了close()?如果没有,这可能是导致内存不足错误的原因。