在Java中将大型hashmap存储到文件中的方法?

时间:2013-08-19 04:27:55

标签: java hashmap

我有一个包含20000个条目的散列图。 hashmap的格式为

Map<Integer,Map<String,Object>> mapOne

我有将地图写入文件的方法。

public void createFiles(String fileName, Map map) throws IOException {
        FileOutputStream fos = new FileOutputStream(fileName);
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        oos.writeObject(map);
        oos.close();
}

此方法通过尝试将mapOne写入文件时的java堆空间错误。有没有其他更好的方法将地图存储到文件中供以后使用?

JDK版本:1.7.0_17 mapOne中的地图包含唯一的元素,其中包含地图中对象的频率。

获得的错误消息:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.io.ObjectOutputStream$HandleTable.growEntries(Unknown Source)
    at java.io.ObjectOutputStream$HandleTable.assign(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at java.util.HashMap.writeObject(Unknown Source)
    at sun.reflect.GeneratedMethodAccessor3.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at java.util.HashMap.writeObject(Unknown Source)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at java.io.ObjectStreamClass.invokeWriteObject(Unknown Source)
    at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
    at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
    at java.io.ObjectOutputStream.writeObject0(Unknown Source)
    at java.io.ObjectOutputStream.writeObject(Unknown Source)
    at TestIndex.AlignReads.createFiles(AlignReads.java:458)
    at TestIndex.AlignReads.loadInputFiles(AlignReads.java:241)
    at TestIndex.AlignReads.<init>(AlignReads.java:126)
    at TestIndex.AlignReads.main(AlignReads.java:493)

2 个答案:

答案 0 :(得分:0)

这似乎不是一个非常大的HashMap。在调用程序时,应考虑增加堆(“内存”)大小。对于Oracle的JDK版本1.7.0_17,可以使用命令行开关-Xms1g -Xmx1g完成此操作。此示例将最大堆设置为1 GB。为了使其变得完全有效,机器必须具有足够的(虚拟)内存资源。默认值可以低至64 MB(低于1 GB的10%),具体取决于具体条件。

关于你的第二个问题,你需要指出你认为“更好”的东西。也就是说,在大多数情况下,使用标准对象序列化API是最佳选择。

第二种最常见的替代方案(有些人可能会说它确实是第一种)是将信息存储在数据库中并根据需要从该信息构造对象。显然,如果出于某种原因你需要同时在内存中获取所有信息,那么你的进步就不多了。

第三种替代方法(在某些情况下,由于某些原因,在这种特殊情况下,对象序列化API行为不当(我怀疑))是有效的,不是一次序列化整个地图,而是每个元素。甚至每个数据项。这要求您在标准API之上定义特定于应用程序的序列化协议。不是很困难,但可能需要另外一个问题。

答案 1 :(得分:0)

也许,您正在序列化引用您不希望序列化的大对象的对象。取自java.awt.Component javadoc

的示例
  

开发人员将一如既往地考虑其影响   使对象可序列化。需要注意的一个问题是:

import java.awt.*;
import java.awt.event.*;
import java.io.Serializable;

class MyApp implements ActionListener, Serializable
{
    BigObjectThatShouldNotBeSerializedWithAButton bigOne;
    Button aButton = new Button();

    MyApp()
    {
        // Oops, now aButton has a listener with a reference
        // to bigOne!
        aButton.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e)
    {
        System.out.println("Hello There");
    }
}
  

在此示例中,单独序列化aButton将导致MyApp及其引用的所有内容也被序列化。该   问题是听众是巧合的序列化,而不是   设计。