首页 > 解决方案 > Files.lines 的高内存使用率

问题描述

我在 SO 上发现了一些其他问题,这些问题与我需要的很接近,但我无法弄清楚。我正在逐行读取文本文件并出现内存不足错误。这是代码:

System.out.println("Total memory before read: " + Runtime.getRuntime().totalMemory()/1000000 + "MB");
String wp_posts = new String();
try(Stream<String> stream = Files.lines(path, StandardCharsets.UTF_8)){
    wp_posts = stream
            .filter(line -> line.startsWith("INSERT INTO `wp_posts`"))
            .collect(StringBuilder::new, StringBuilder::append,
                    StringBuilder::append)
            .toString();
} catch (Exception e1) {
    System.out.println(e1.getMessage());
    e1.printStackTrace();
} 

try {
    System.out.println("wp_posts Mega bytes: " + wp_posts.getBytes("UTF-8").length/1000000);
} catch (UnsupportedEncodingException e) {
    e.printStackTrace();
}
System.out.println("Total memory after read: " + Runtime.getRuntime().totalMemory()/1000000 + "MB");

输出类似于(在内存更多的环境中运行时):

Total memory before read: 255MB
wp_posts Mega bytes: 18
Total memory after read: 1035MB

请注意,在我的生产环境中,我无法增加内存堆。

我已经尝试显式关闭流,执行 gc,并将流置于并行模式(消耗更多内存)。

我的问题是:这是预期的内存使用量吗?有没有办法使用更少的内存?

标签: java

解决方案


你的问题在collect(StringBuilder::new, StringBuilder::append, StringBuilder::append). 当您将 smth 添加到StringBuilder并且它没有足够的内部数组时,它会将其加倍并从前一个数组中复制一部分。

执行new StringBuilder(int size)预定义内部数组的大小。

第二个问题,是你有一个大文件,但结果你把它放到了StringBuilder. 这对我来说很奇怪。实际上,这与将整个文件读入 aString而不使用Stream.


推荐阅读