Java字符串内存泄漏

Avi*_*ash 7 java memory garbage-collection memory-leaks 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Pet*_*rey 6

您好,我不是java专家.

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

我的代码是将文件读入String,此代码每5分钟执行一次.现在有时文件大小为100行有时为1000行.

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

几天后,我经历了记忆.

您应该能够获得堆转储并查看内存不足的原因以及原因.

我的问题是,当我的代码超出了阅读文件功能的范围.Java Garbage是否收集String.

当无法通过强引用访问它时,可以收集它.

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

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


Ope*_*uce 5

您的read方法永远不会终止.一旦你到达文件的末尾,你只要继续添加字符串"nullabcd"s永远.

编辑:忘了,s每次重新分配.不过,我看不出你的read方法如何终止.


Ste*_*n C 4

您发布的代码不会泄漏内存。但是,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");
    }
Run Code Online (Sandbox Code Playgroud)

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

每次我们执行时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");
    }
Run Code Online (Sandbox Code Playgroud)

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


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