使用大型数据结构时,避免 Java(eclipse) 中的“内存不足错误”?
-
20-09-2019 - |
题
好的,所以我正在编写一个程序,不幸的是需要使用巨大的数据结构来完成其工作,但它在初始化期间因“内存不足错误”而失败。虽然我完全理解这意味着什么以及为什么这是一个问题,但我很难克服它,因为我的程序需要使用这个大型结构,并且我不知道任何其他方式来存储它。
该程序首先索引我提供的大量文本文件。这很好用。
然后它使用这个索引来初始化一个大的二维数组。该数组将有 n² 个条目,其中“n”是文本语料库中唯一单词的数量。对于相对较小的块,我正在(大约 60 个文件)上进行测试,它需要创建大约 30,000x30,000 个条目。一旦我在完整的预期语料库上运行它,它可能会更大。
在索引之后,在初始化数据结构(稍后处理)时,它每次都会失败。
我做过的事情包括:
- 修改我的代码以使用原语
int[]
代替TreeMap
- 消除冗余结构等...
- 另外,我已经运行了该程序
-Xmx2g
最大化我分配的内存
我相当有信心这不会是一个简单的代码行解决方案,但很可能需要一种非常新的方法。我正在寻找这种方法是什么,有什么想法吗?
谢谢,B。
其他提示
内存不足问题的原因有多种。
首先,最简单的情况是您只需要更多堆。当您的程序可以在 2G 下正常运行时,您正在使用 512M 最大堆。增加是与 -Xmx2048m
作为 JVM 选项,你就可以了。另请注意,64 位 VM 使用的内存最多是 32 位 VM 的两倍,具体取决于数据的构成。
如果您的问题不是那么简单,那么您可以考虑优化。用原语替换对象等等。这可能是一个选择。根据您发布的内容,我真的无法说。
然而最终你来到了一个十字路口,你必须在两者之间做出选择 虚拟化 和 划分.
虚拟化 在这种情况下,仅仅意味着某种形式的假装内存比实际多。操作系统将其与虚拟地址空间结合使用,并使用硬盘空间作为额外内存。这可能意味着一次仅将一些数据结构保留在内存中,并将其余数据结构持久保存到辅助存储(例如文件或数据库)。
分区 将您的数据分散到多个服务器(真实的或虚拟的)。例如,如果您要跟踪纳斯达克的股票交易,您可以在服务器 1 上输入以“A”开头的股票代码,在服务器 2 上输入以“B”开头的股票代码,等等。您需要找到一种合理的方法来分割数据,以便减少或消除交叉通信的需要,因为交叉通信限制了您的可扩展性。
如此简单的情况,如果您要存储的是 30K 单词和 30K x 30K 单词组合,您可以将其分为四个服务器:
- A-M x A-M
- A-M x N-Z
- N-Z x A-M
- N-Z x N-Z
这只是一个想法。同样,在不了解具体情况的情况下很难发表评论。
这是处理大型数据集的常见问题。您可以根据需要进行优化,但内存永远不会足够(可能),并且一旦数据集增长一点,您仍然会被熏。最具可扩展性的解决方案就是减少内存占用,处理块,并将结构保留在磁盘(数据库/文件)上。
如果您的 2D 数组中的每个值不需要完整的 32 位(整数大小),也许更小的类型(例如字节)可以解决问题?此外,您还应该为其提供尽可能多的堆空间 - 对于现代系统来说 2GB 仍然相对较小。RAM 很便宜,尤其是当您希望在内存中进行大量处理时。