HashMap <String, Double>
中。然而,程序报告了“内存不足”错误。我尝试增加堆大小到 -Xmx15000M
,但是程序会运行半小时后再次抛出相同的异常。从中读取单词和频率的文件大小为1.7GB。非常感谢任何的帮助。
谢谢 :-)
HashMap <String, Double>
中。然而,程序报告了“内存不足”错误。我尝试增加堆大小到 -Xmx15000M
,但是程序会运行半小时后再次抛出相同的异常。从中读取单词和频率的文件大小为1.7GB。对于这样的文字处理,通常使用树而不是哈希表来处理,如果你可以忍受更长的查找时间。该结构对自然语言而言具有相当高的内存效率,其中许多单词具有共同的起始字符串。
根据输入的情况,一棵Patricia树可能会更好。
(此外,如果这确实是自然语言中的单词,请确保您真的需要1亿个条目吗?常用单词的数量令人惊讶地低,商业解决方案(词预测、拼写矫正)很少使用超过100,000个单词,无论哪种语言。)
你的问题在于1.7 GB原始文本即使不考虑字符串对象的开销,也超过了1500 MB。对于大型映射,你应该使用数据库或基于文件的Map,它们会使用磁盘内存而不是堆内存。
更新
我认为为堆分配15 GB的内存对于大多数jvm来说是不可能的。它不适用于任何32位的jvm,我也不认为64位的jvm会工作。 当足够的RAM可用时,64位jvm应该可以使用15 GB的内存。
如上所述,有几种地图实现没有这些问题。由于您将数字存储在地图中,因此额外的好处是,当您将新值放入地图或更新旧值时,无需不断在对象和原始类型之间切换(即装箱/拆箱),因此您将获得性能提升。可以在{{link3:Java性能调整指南上的此帖子}}中找到适用于大量数据的各种原始哈希映射的基准:
如果你有一亿个术语,那么几乎肯定超出了内存存储的限制。将术语存储在某种数据库中,可以使用商业数据库,也可以编写允许您访问文件以获取所需信息的程序。如果您拥有的文件格式不允许您快速访问文件,则将其转换为可以快速访问文件的格式,例如使每个记录成为固定大小,这样您就可以立即计算任何记录编号的文件偏移量。然后对记录进行排序,就可以非常快速地进行二进制搜索。您还可以编写代码,无需将整个文件存储在内存中即可大大加快对文件的访问。
您还可以尝试使用词干提取来增加重复项的数量。
例如,cat = Cats = cats = Cat
或者
swim = swimming = swims
尝试在Google上搜索“Porter Stemmer”。
public class Phrase {
private final String[] interned;
public Phrase(String phrase) {
String[] tmp = phrase.split(phrase, "\\s");
this.interned = new String[tmp.length];
for (int i=0; i<tmp.length; ++i) {
this.interned[i] = tmp[i].intern();
}
}
public boolean equals(Object o) { /* TODO */ }
public int hashCode() { /* TODO */ }
}
Trove THashMap使用的内存要少得多。不过,我怀疑这是否足以减小尺寸。除了严格在内存中检索之外,您需要其他地方来存储此信息。