2

我有一个包含 20000 个条目的哈希图。哈希图的形式是,

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)
4

2 回答 2

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 及其引用的所有内容也被序列化。问题是侦听器是巧合的序列化,而不是设计。

于 2013-08-19T06:20:43.380 回答
0

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

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

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

第三种选择(如果由于某种原因对象序列化 API 在这种特殊情况下行为不端(我怀疑)有效),不是序列化整个地图,而是一次序列化每个元素。甚至是每个数据项。这需要您在标准 API 之上定义特定于应用程序的序列化协议。不是非常困难,但可能值得一个单独的问题。

于 2013-08-19T04:34:03.690 回答