将文件内容存储到StringBuilder显然需要太多内存

时间:2014-08-18 14:20:52

标签: java file io

我有这段代码:

public static void main(String[] args) {
    System.out.println("Reading file...");
    String content = readFile(args[0]);
    System.out.println("Done reading file.");
}

private static String readFile(String file) throws IOException {
    BufferedReader reader = new BufferedReader( new FileReader (file));
    String         line = null;
    StringBuilder  stringBuilder = new StringBuilder();
    while( ( line = reader.readLine() ) != null ) {
        stringBuilder.append( line );
    }

    return stringBuilder.toString();
}

readFile方法适用于小文件。

我注意到的是它需要太多记忆。

如果我在Windows上打开系统监视器(CTRL-SHIFT-ESC),我看到java进程占用高达1.8GB的RAM,而我的文件大小只有550MB。

是的,我知道,将文件完全加载到内存中并不是一个好主意,我这样做只是为了好奇。

当新创建的java进程启动时,程序卡在Reading file...,它需要一堆MB的RAM并且最高可达1.8GB。

我也尝试使用字符串连接而不是使用StringBuilder,但我的结果完全相同。

为什么需要这么多内存?最终的stringBuilder.toString导致了这个吗?

1 个答案:

答案 0 :(得分:3)

您必须记住这些库的工作原理。

磁盘上的一个字节可以变成2字节的字符。 StringBuilder的容量增加了一倍,因此它可以达到你真正需要的两倍,并且你需要同时在内存中同时使用StringBuilder和String。

以你的榜样为例。单独char可将550 MB变为1100 MB。但是,大小增加了一倍,因此它大约是2的下一个幂,即它可能是2 GB,这是一个字符串,它将是550 MB。

注意:它没有使用这么多内存的原因是你有一个bug。您丢弃所有新行\r\n,这意味着您的字符数较少。


当处理一个没有足够内存的大文件一次将其加载到内存中时,最好在阅读时处理数据。

BTW如果你有足够的内存,你可以用更少的内存来更快地读取文件。

static String readFile(String file) throws IOException {
    try(FileInputStream fis = new FileInputStream(file)) {
         byte[] bytes = new byte[(int) fis.available()];
         fis.read(bytes);
         return new String(bytes);
    }
}