加载226MB文本文件时的内存使用情况

时间:2017-04-07 16:55:17

标签: java file memory text load

我必须阅读一个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的矢量。 谢谢你的回答。

2 个答案:

答案 0 :(得分:3)

这里有多种效果。

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

您的阅读代码很乐意产生大量的垃圾对象 - 您再次使用包装类型(Integer)来解决简单的int会执行的数组。这至少有16个字节的垃圾,其中int为零。 String.split是另一个罪魁祸首,你强制每行编译两个正则表达式,再加上创建两个字符串。这是许多短生物,每一行都成了垃圾。所有这些都可以通过几行代码来避免。

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

TLDR:读取代码效率低,没有JVM参数。

答案 1 :(得分:0)

如果您生成了文件,请使用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 remaining string。