ArrayList<ArrayList<String>>超出内存限制 (Java堆空间)。 是否有其他选项?

3

我正在使用ArrayList数据结构处理csv文件。我的机器非常强大: 内存:8GB RAM 处理器:4个CPU,每个i5 Intel core 2.5GHz。

在eclipse中,我使用运行配置的vm参数面板分配了-Xmx5120m(5GB RAM用于java虚拟机)。

如果我的ArrayList<ArrayList<String>>超过约468000 X 108,我仍然会遇到“outofmemory java heap space”的问题。我使用arraylist是因为我感觉它最舒适,并且易于处理我的目的数据。

实际上,我正在使用这个二维数组进行基于列的上下文处理,例如:

arraylist.get(i).get(0) 

where

0 < i < 468000 

一个arrayList可以代表一列。由于我要进行的操作(例如用另一列替换一列、复制一列、在arrayList中任意位置插入一列等),我只能想到使用arrayList,因为它在平均情况下添加或插入元素具有摊销常数时间。

现在我的问题是:

除了arrayList之外,还有哪些数据结构可以让我达到比468000 X 108大得多的数量级(例如像(833 * 1000000) X 108这样),并且能够执行我上面提到的所有操作?(但我仍然希望能够使用我的机器容量进行操作)

我可以考虑按顺序处理所有这些内容,也就是先处理468000 X 108并将其写入csv文件,然后再将其加载到468000 X 108的arrayList中并将其写入不同的文件等等...

我不认为我已经达到了arrayList的极限。

我会非常感激任何形式的帮助。


1
假设您正在使用4字节整数,您需要(833 * 1000000 X 108)* 4 = 359 856 000 000字节的内存,或者超过350千兆字节,因此很容易出现内存不足错误。 :D - Gordon Gustafson
5
我建议您重新考虑您的方法。您是否真正需要一次性将所有内容存储在内存中?还是您只需要一次了解一行内容?您并没有提供关于您正在处理的所有数据及其来源的详细信息,只是说它们非常多。如果您确实需要能够访问任何给定的行和列,我建议您将所有数据放入数据库中,并进行查询。 - matt
分成256个部分?也许吧?哈哈!:D - Grayson Peddie
2
@CrazyJugglerDrummer,情况比那还要糟糕。833 * 1000000 * 108是条目数。每个条目至少为8字节(64位VM上的引用大小)。因此,仅对象引用所需的内存大小就为670 GiB。 - rlibby
3个回答

4
你正在尝试将一份有468,000行的文件塞入5G内存中,但内存不足。
数据结构并不是问题所在。
你需要改变方法,按块处理文件,只提取所需数据等。

我并不需要同时拥有所有数据。但是逐个复制条目(以便可以复制列)也不是一个好选择,因为我将从硬盘访问文件,对于这么多的数据,文件的访问次数会导致性能问题。您能否提供更详细的建议? - Programmer
很不幸,使用那么多的数据尝试将其放入RAM中会导致性能问题,甚至会崩溃。如果一次无法将所有数据都装入内存中,您必须使用磁盘。这也是数据库的工作原理。 - Brian Roach

1

在ArrayList中的任意位置插入元素并不能保证平摊常数时间,因为列表内部必须进行复制操作。只有在插入到末尾时才能使用这种方法。

此外,当ArrayList需要增长时,它会通过以下方式计算新的大小:

  int newCapacity = (oldCapacity * 3)/2 + 1;

在您的情况下,使用自定义大小的字符串数组而不是列表(或者至少在读取完列后调用trimToSize())会更有效率,因为列表可能会浪费大量内存。

只要您每次只需要几列数据,我建议将每一列存储在单独的文件中,这样您可以按需加载/写入 - 如果它们只包含字符串,您可以考虑一些易于阅读的二进制格式,并使用DataOutputStream和-InputStream。插入列只需进行文件重命名操作...您还可以添加一些缓存,以保留最近或最常使用的列(搜索java.util.LinkedHashMap以了解简单LFU-Cache的想法)。如果您不需要事务等,请勿使用数据库,也不要以XML等冗长格式存储此类数据,否则性能将大幅降低。

最后,我建议您考虑矩阵的内容,因为字符串可能会变得非常庞大:您真的需要它们作为字符串吗?或者您可以创建一个占用更少内存的表示方式?例如,如果您只有60,000个不同的字符串,您可以创建它们与short之间的映射,并在内存中使用shorts。


0
一个好的“改变你的方法”的方式,正如其他人所建议的那样,是将你的数据持久化在数据库或XML文件中,然后根据需要使用较小的数据子集进行操作。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接