【问题标题】:Memory usage in loading a 226MB text file加载 226MB 文本文件时的内存使用情况
【发布时间】:2017-09-03 03:39:37
【问题描述】:

我必须阅读这样制作的 226mb 的文本文件:

0 25
1 1382
2 99
3 3456
4 921
5 1528
6 578
7 122
8 528
9 81

第一个数字是索引,第二个是值。我想加载一个短读这个文件的向量(8349328个位置),所以我写了这段代码:

    Short[] docsofword = new Short[8349328];

        br2 = new BufferedReader(new FileReader("TermOccurrenceinCollection.txt"));             
        ss = br2.readLine();
        while(ss!=null)
        {
            docsofword[Integer.valueOf(ss.split("\\s+")[0])] = Short.valueOf(ss.split("\\s+")[1]);  //[indexTerm] - numOccInCollection
            ss = br2.readLine();
        }
    br2.close();

事实证明,整个负载占用了令人难以置信的 4.2GB 内存。真的我不明白为什么,我期望一个 15MB 的向量。 感谢您的任何回答。

【问题讨论】:

  • 您如何确定内存使用情况?请记住Shortshort 不同;每个元素都有一个额外的引用(指针)。

标签: java file memory text load


【解决方案1】:

这里有多种效果。

首先,您将数组声明为 Short[] 类型,而不是 short[]。前者是一个引用类型,这意味着每个值都被包装到一个 Short 实例中,消耗了一个完整对象的开销(很可能是 16 个字节而不是两个字节)。这也会将每个数组槽从两个字节膨胀到参考大小(通常为 4 或 8 个字节,具体取决于堆大小和 32/64 位 VM)。因此,完全填充数组的最小大小约为:8349328 x 20 = 160MB。

您的阅读代码正在愉快地产生大量垃圾对象 - 您再次使用包装器类型(整数)来处理简单 int 可以执行的数组。那是至少 16 个字节的垃圾,其中 int 为零。 String.split 是另一个罪魁祸首,你强制每行编译两个正则表达式,再加上创建两个字符串。那是许多短暂的对象,它们成为每一行的垃圾。只需多写几行代码,所有这些都可以避免。

所以你有一个相对需要内存的数组,还有很多垃圾。可以清理垃圾内存,但 JVM 决定何时。该决定基于可用的最大堆内存和垃圾收集器参数。如果您没有提供任何参数,JVM 会在尝试回收垃圾之前愉快地填充您的机器内存。

TLDR:无 JVM 参数配对的低效读取代码。

【讨论】:

  • 很好的答案,虽然我质疑“JVM 会愉快地填满你机器的内存”——总是有一个默认的 Xmx 值。
  • 感谢@Durandal,您永远不会停止学习,感谢您,我理解了我的错误。发布此问题后,我发现了 Short-short 错误,但我完全不知道有多少垃圾会产生 String.split,谢谢。
【解决方案2】:

如果文件是你自己生成的,使用objectOutputStream,读取文件非常简单。

作为@Durandal,相应地更改代码。我在下面给出示例代码。

short[] docsofword = new short[8349328];

    br2 = new BufferedReader(new FileReader("TermOccurrenceinCollection.txt"));             
    ss = br2.readLine();
    int strIndex, index;
    while(ss!=null)
    {
       strIndex = ss.indexOf( ' ' );
       index = Integer.parseInt(ss.subStr(0, strIndex));
       docsofword[index] = Short.parseShort(ss.subStr(strIndex+1));
       ss = br2.readLine();
    }
br2.close();

即使您可以进一步优化。我们可以编写自己的方法代替 indexOf(),当 char 匹配空格时,将字符串解析为整数。之后我们会得到 indexOf Space 和 index for get 的剩余字符串。

【讨论】:

  • @user3329403 检查并告诉我,以便我提供更多建议/代码
  • 谢谢@Jitendra Kumar。巴拉,我理解我的错误。我在发布问题后发现了“Short-short”错误,但我不知道有多少垃圾会产生 String.split。你的代码有一些索引错误(子字符串最后一个索引是独占的,所以它不需要-1),但它工作得很好,谢谢
  • @user3329403 感谢您的回复。解决后你能接受解决方案吗?
猜你喜欢
  • 2010-11-17
  • 1970-01-01
  • 1970-01-01
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多