在Java中读取字典文件时内存太大

时间:2015-05-15 03:55:36

标签: java memory dictionary

我读了一个大小可能是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文件,但我仍然收到错误。

更新:我修复了文件的一些迭代,现在内存问题已部分解决了。然而,尝试房产和其他解决方案并报告。

4 个答案:

答案 0 :(得分:1)

您正在为每一行分配一个新字符串。有一些与String相关的开销。有关计算,请参阅HereThis文章还讨论了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将其存储在文件中并进行散列,然后在运行时从文件中获取搜索结果,但有效。这个保存很多内存。您可以自定义搜索取决于您的需求

Small Demo of Lucene

答案 3 :(得分:0)

这个问题的一些原因是。

1)。字符串数组cols耗尽了太多内存。

2)。字符串line也可能使用太多内存,但不太可能。

3)。当java打开并读取文件时,它也使用内存,这也是一个概率。

4)。您的地图put也会占用少量内存。

也可能是所有这些事情结合在一起,所以也许尝试并评论一些行,看看是否有效。

最可能的原因是所有这些东西加起来就是在吃你的记忆。因此,一个10兆字节的文件最终可能会达到50兆字节。还要确保.close()所有输入流并尝试通过拆分方法来重新分配ram,以便变量被垃圾收集。

至于这样做而不改变包结构或java堆大小参数我不确定它是否会非常容易,如果可能的话。

希望这有帮助。