我想存储100个亿术语和它们的频率(在文本数据库)成HashMap <String, Double>.它给了我"Out of Memory"错误.我试图将堆空间增加到-Xmx15000M.然而,它运行半小时然后再次抛出相同的异常.从中我想读的话和频率的文件大小为1.7GB.
任何帮助将非常感激.
谢谢 :-)
Chr*_*fer 16
对于像这样的文字处理,答案通常是树而不是散列图,如果你可以忍受更长的查找时间.对于自然语言来说,这种结构非常有效,因为许多单词都有共同的起始字符串.
根据输入,Patricia树可能会更好.
(另外,如果这确实是来自自然语言的单词,你确定你真的需要100,000,000个条目吗?大多数常用单词都非常低,商业解决方案(单词预测,拼写纠正)很少使用超过100,000个单词而不管语言.)
jos*_*efx 11
您的问题是1.7 GB原始文本超过1500 MB,即使没有单个字符串对象添加的开销.对于巨大的映射,您应该使用数据库或文件支持的Map,这些将使用磁盘内存而不是堆.
更新
我不认为为大多数jvms分配15 GB的堆是可能的.它不适用于任何32位jvm,我不认为64位jvm也可以工作.当有足够的RAM可用时,15 GB的内存应该可以在64位jvm上运行.
如果您只想要一个轻量级的 KeyValue(Map)存储,我会考虑使用 Redis。它速度非常快,并且能够在需要时保留数据。唯一的缺点是您需要在 Linux 计算机上运行 Redis 存储。
如果您仅限于 Windows,并且可以在 64 位中运行,MongoDB 是一个不错的选择。
有了1亿个术语,你几乎可以肯定超过应该存储在内存中的限制.将您的条款存储在某种数据库中.要么使用商业数据库,要么写一些允许您访问文件以获取所需信息的内容.如果您拥有的文件格式不允许您快速访问该文件,那么将其转换为一个文件格式 - 例如,使每个记录的大小固定,这样您就可以立即计算任何记录号的文件偏移量.对记录进行排序将允许您非常快速地进行二进制搜索.您还可以编写代码来大大加快对文件的访问速度,而无需将整个文件存储在内存中.
一个1.7 GB的文件是一个相对较小的文件来执行此操作并存储在RAM中.我用更大的文件执行此操作并将它们存储在内存中而没有任何问题.可以使用数据库,但可能过度或完美,具体取决于您计划对数据执行的操作.
正如其他人所说,使用自然语言,可能会有相对较少的唯一值,因此地图实际上不会那么大.我不会使用java.util.HashMap,因为它在内存使用方面效率非常低,尤其是在存储诸如int的原始值时.java.util.HashMap将基元存储为对象.它还将每个值存储在浪费内存的HashMap.Entry对象中.由于这两个因素,java.util.HashMap使用的内存比Trove,Fastutil等其他内容要多得多:
如上所述,有几种地图实现没有这些问题.由于您在地图中存储数字,因此您可以获得性能提升,因为您无需在对象和基元之间不断切换(即装箱/拆箱),因为您要在地图中添加新值或更新旧值值.可以在Java性能调优指南的这篇文章中找到更适合大量数据的各种原始哈希图的基准: