我读了一个大小可能是100MB左右的字典(有时会变大到最大500MB)。它是两列的简单字典,第一列是第二列的浮点值。我用这种方式阅读了字典file
:
BufferedReader br = new BufferedReader(new FileReader(file));
String line;
while((line = br.readLine()) != null) {
String[] cols = line.split("\t");
setIt(cols[0], cols[1]);
和setIt
函数:
public void setIt(String term, String value) {
all.put(term, new Double(value));
}
当我有一个大文件时,加载它需要很长时间,并且它经常会耗尽内存。即使使用合理大小的文件(100MB),它也需要运行Java中的4GB内存。
有什么线索如何在不改变整个包装结构的情况下改进它?
编辑:我使用带有-Xmx1g
的50MB文件,但我仍然收到错误。
更新:我修复了文件的一些迭代,现在内存问题已部分解决了。然而,尝试房产和其他解决方案并报告。
答案 0 :(得分:1)
您正在为每一行分配一个新字符串。有一些与String相关的开销。有关计算,请参阅Here。 This文章还讨论了java中对象内存使用的主题。
关于字符串here的更多内存有效替换的主题存在堆栈溢出问题。
你能做些什么来避免所有这些分配?例如,您是否可以在数据结构中将有限数量的字符串表示为整数,然后使用较小的查找表进行翻译?
答案 1 :(得分:1)
您可以做很多事情来减少内存使用量。例如:
1-将String[] cols = line.split("\t");
替换为:
static final Pattern PATTERN = Pattern.compile("\t");
//...
String[] cols = PATTERN.split(line);
2-使用.properties
文件来存储你的字典,只需这样加载:
Properties properties = new Properties();
//...
try (FileInputStream fileInputStream = new FileInputStream("D:/dictionary.properties")) {
properties.load(fileInputStream);
}
Map<String, Double> map = new HashMap<>();
Enumeration<?> enumeration = properties.propertyNames();
while (enumeration.hasMoreElements()){
String key = (String) enumeration.nextElement();
map.put(key, new Double(properties.getProperty(key)));
}
//...
dictionary.properties:
A = 1
B = 2
C = 3
//...
3-使用StringTokenizer
:
StringTokenizer tokenizer = new StringTokenizer(line, "\t");
setIt(tokenizer.nextToken(), tokenizer.nextToken());
答案 2 :(得分:1)
我的解决方案与您的代码略有不同......
使用Lucene或更具体的Lucene Dictionary或更具体的Lucene Spell Checker取决于您的需求。
Lucene使用高效内存使用来处理任意数量的数据..
你的问题是你将整个字典存储在内存中... Lucene将其存储在文件中并进行散列,然后在运行时从文件中获取搜索结果,但有效。这个保存很多内存。您可以自定义搜索取决于您的需求
答案 3 :(得分:0)
这个问题的一些原因是。
1)。字符串数组cols
耗尽了太多内存。
2)。字符串line
也可能使用太多内存,但不太可能。
3)。当java打开并读取文件时,它也使用内存,这也是一个概率。
4)。您的地图put
也会占用少量内存。
也可能是所有这些事情结合在一起,所以也许尝试并评论一些行,看看是否有效。
最可能的原因是所有这些东西加起来就是在吃你的记忆。因此,一个10兆字节的文件最终可能会达到50兆字节。还要确保.close()
所有输入流并尝试通过拆分方法来重新分配ram,以便变量被垃圾收集。
至于这样做而不改变包结构或java堆大小参数我不确定它是否会非常容易,如果可能的话。
希望这有帮助。