Java 字符串内存泄漏

发布于 2024-11-08 20:10:27 字数 1460 浏览 0 评论 0原文

我不是java专家。

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

几天后,我经历了“内存不足”。

我的问题是,当我的代码超出读取文件函数的范围时,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();
    }
}

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

初心 2024-11-15 20:10:27

您好,我不是java专家。

每个人都有可以学习的东西。

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

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

几天后,我遇到了“内存不足”的情况。

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

我的问题是,当我的代码超出读取文件功能的范围时。 Java 垃圾是否收集 String 。

当不再可以通过强引用访问它时,可以收集它。

我在网上读到一些人说它不会被删除并使用 StringBuffer ,这让我很困惑

听起来很困惑,听起来你来对地方了。我从来没有听说过这个。

Hello, I am not java expert.

Everyone has something they can learn.

My code is reading a file into a String, This code gets executed every 5 minutes. Now Sometime file size of 100 lines sometimes 1000 lines.

Doesn't sound very large or very often. Shouldn't be a problem.

I am experience Out Of Memory, after some days.

You should be able to get a heap dump and see where you have run out of memory and why.

Question I have is, When my codes goes out of scope of the Reading file Function. Does Java Garbage collect the String .

It can be collected when it is no longer reachable via a Strong reference.

I am pretty confuse by reading on internet some says it does not get deleted and use StringBuffer

Sounds like you came to the right place. I have never heard that one.

疏忽 2024-11-15 20:10:27

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

编辑:忘记了,s 每次都会重新分配。尽管如此,我还是看不出你的 read 方法如何终止。

Your read method will never terminate. Once you reach the end of the file, you just continue adding the string "nullabcd" to s, forever.

EDIT: forget that, s is re-assigned each time. Still, I can't see how your read method can terminate.

有木有妳兜一样 2024-11-15 20:10:27

您发布的代码不会泄漏内存。但是,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< /code> 字符。


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

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.

九歌凝 2024-11-15 20:10:27

像下面这样更改程序以消耗更少的内存。内存消耗的一个巨大来源是由于您重复的字符串连接 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");
}

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; <--- 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");
}
余罪 2024-11-15 20:10:27

正如其他人指出的那样,这段代码永远不会终止。您发布的代码似乎不是您遇到问题的原始代码。

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

大胆猜测:使用完 Readers 和 InputStreams 后,您是否会调用 close() ?如果没有,这可能是内存不足错误的原因。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文