【问题标题】:Storing file contents to StringBuilder apparently takes too much memory将文件内容存储到 StringBuilder 显然会占用太多内存
【发布时间】:2014-08-18 14:20:51
【问题描述】:

我有这个代码:

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...,它需要大量的 RAM 并上升到 1.8GB。

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

为什么要占用这么多内存?是最终的stringBuilder.toString 造成的吗?

【问题讨论】:

  • 我也尝试使用字符串连接而不是使用 StringBuilder,但我得到了完全相同的结果。 - 如果使用字符串,我担心结果会更糟跨度>
  • 如果您的问题是内存,只需使用扫描仪读取文件

标签: java file io


【解决方案1】:

您必须记住这些库是如何工作的。

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

那么就拿你的例子来说吧。单独的char 可以将 550 MB 变成 1100 MB。但是,大小会翻倍,因此它将大约是 2 的下一个幂,即它可能是 2 GB,这是在 550 MB 的字符串之上。

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


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

顺便说一句,如果你有足够的内存,你可以更快地读取文件,这样用更少的内存。

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

【讨论】:

  • 它没有使用这么多内存的原因是你有一个错误。您正在丢弃所有新行好吧,这不是错误,我这样做是因为我需要丢弃它们:) 无论如何,谢谢,现在一切都清楚了:) 是的,您的方法要快得多并且占用更少的内存,这很棒。
  • @BackSlash 进一步减少它我会使用内存映射文件。这将几乎不使用任何堆。
  • 呃!我不知道内存映射文件...我正在看MappedByteBuffer,再次感谢您! :)
  • @BackSlash 这使您可以像使用内存一样使用文件,而无需将其放入堆中。我已经使用内存映射映射了一个 100 TB 的文件。
  • 但是如果我将内容存储到一个字符串中(完整的内容,或者只是它的一小部分),我认为它会将字符串分配到堆中......我是对的吗?跨度>
猜你喜欢
  • 2015-10-14
  • 2013-07-18
  • 2013-07-11
  • 2020-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-26
  • 1970-01-01
相关资源
最近更新 更多