Java字符串内存泄漏 [英] Java String Memory Leak

查看:158
本文介绍了Java字符串内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不是java专家。

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



我经历了一段时间之后的内存不足。



我的问题是,当我的代码超出了读取文件函数的范围时,Java垃圾收集了字符串吗?



通过在互联网上阅读,我感到非常困惑。有些人说它不会被删除并使用 StringBuffer

  / /演示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 =新的FileReader(big_file.txt.1);
br = new BufferedReader(fr);
read(br);
fr =新的FileReader(big_file.txt.1);
br = new BufferedReader(fr);
read(br);
fr =新的FileReader(big_file.txt.1);
br = new BufferedReader(fr);
read(br);
BufferedReader in = new BufferedReader(new InputStreamReader(System。in));在.readLine();
fr.close();
}
}


解决方案

你发布的代码不会泄漏内存。然而, 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读取(BufferedReader br)抛出异常{
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);



$ b $ p
$ b

该版本将重新分配StringBuilder的内部字符数组至多 em> log2(N)次数并复制至多 2 * N * L 字符。




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


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

解决方案

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.

这篇关于Java字符串内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆