我正在使用 ArrayList数据结构来处理cvs文件。我的机器非常强大: 记忆:8 GB的Ram 处理器:4个CPU,每个i5 Intel核心2.5GHz
在eclipse中,我使用Run as-> Configuration中的vm arguments面板分配了-Xmx5120m(java vm的5GB RAM)。
如果它超过468000 X 108,我仍然为我的ArrayList<ArrayList<String>>
获得“outofmemory java heap space”。我正在使用arraylist,因为我觉得自己最熟悉它并且它可以很容易地处理我的目的数据。
实际上,我将这个二维数组用于基于列的上下文,比如
arraylist.get(i).get(0)
其中
0 < i < 468000
代表一列。由于我执行的操作(用另一列替换列,复制列,将列插入arrayList中的任意位置等),我只能想到arrayList,因为它已经分摊了常量时间来添加或插入到arraylist在其平均情况下。
所以现在我的问题是:
我可以使用哪些其他数据结构代替arraylist以达到远远超过468000 X 108的幅度(例如,像(833 * 1000000)X 108)并且能够执行上面提到的所有操作? (但我仍然希望能够使用我拥有的容量在我的机器上执行此操作)
我可以想到按顺序执行所有这些操作,这意味着首先处理468000 X 108并将其写入csv文件,然后再次加载到468000 X 108 arraylist并将其写入不同的文件等...
我认为我的容量达不到arraylist的限制。
我会感激任何帮助。
答案 0 :(得分:4)
您正在尝试将具有468,000行的文件填充到5G内存中,并且内存不足。
数据结构不是问题。
您需要改变您的方法,而不是那样做。一次处理文件的块,只提取您需要的数据等。
答案 1 :(得分:1)
在ArrayList中的某处插入不会给你分摊的常量时间,因为列表必须在内部复制 - 只有在最后插入时才会有效。
此外,当ArrayList必须增长时,它将通过
计算新的大小 int newCapacity = (oldCapacity * 3)/2 + 1;
这可能会浪费大量内存 - 使用自定义大小的String-array而不是列表(或者在读完列后至少调用trimToSize())会更有效。 / p>
只要你每次只需要几列,我建议将每一列存储在一个单独的文件中,你可以根据需要加载/写入 - 如果它们只包含字符串,你可以想到例如,一些易于阅读的二进制格式,并使用DataOutputStream和-InputStream。插入一个列只会成为文件重命名操作...您还可以添加一些缓存,以保留内存中最新或最常用的列(搜索java.util.LinkedHashMap以了解简单的LFU-Cache )。如果您不需要事务等,请不要使用数据库,不要以XML等详细格式存储此类数据 - 否则会导致巨大的性能损失。
最后,我会考虑矩阵的内容,因为字符串可能变得非常庞大:你真的需要它们作为字符串,还是你可以创建一个消耗较少的内存消耗代表?例如,如果你只有60,000个不同的字符串,你可以在它们之间创建一个映射,并在短时间内使用短消息。
答案 2 :(得分:0)
正如其他人所建议的那样,“改变方法”的好方法是将数据保存在数据库或xml文件中,然后根据需要使用较小的数据子集。