代码之家  ›  专栏  ›  技术社区  ›  Mark Chorley

对象可以在Java序列化过程中缓冲吗?

  •  3
  • Mark Chorley  · 技术社区  · 16 年前

    我有一个非常大的对象要序列化。在序列化过程中,它将占用大约130MB的堆作为weblogic.utils.io.unsyncBytearrayOutputstream。我正在使用BufferedOutputstream来加快将数据写入磁盘的速度,这减少了将此对象保存在内存中的时间量。

    但是,是否可以使用缓冲区来减小内存中对象的大小?如果有一种方法可以一次将它序列化x个字节,并将这些字节写入磁盘,那就太好了。

    如果有任何用途,则遵循示例代码。虽然我不认为还有很多事情要做。如果在这种情况下,需要对要序列化的对象有一个完整的内存中副本(因此没有序列化缓冲区的概念),那么我想我卡住了。

        ObjectOutputStream tmpSerFileObjectStream = null;
        OutputStream tmpSerFileStream = null;
        BufferedOutputStream bufferedStream = null;
        try {
    
            tmpSerFileStream = new FileOutputStream(tmpSerFile);
            bufferedStream = new BufferedOutputStream(tmpSerFileStream);
    
            tmpSerFileObjectStream = new ObjectOutputStream(bufferedStream);
            tmpSerFileObjectStream.writeObject(siteGroup);
            tmpSerFileObjectStream.flush();
    
        } catch (InvalidClassException invalidClassEx) {
            throw new SiteGroupRepositoryException(
                    "Problem encountered with class being serialised", invalidClassEx);
        } catch (NotSerializableException notSerializableEx) {
            throw new SiteGroupRepositoryException(
                    "Object to be serialized does not implement " + Serializable.class,
                    notSerializableEx);
        } catch (IOException ioEx) {
            throw new SiteGroupRepositoryException(
                    "Problem encountered while writing ser file", ioEx);
        } catch (Exception ex) {
            throw new SiteGroupRepositoryException(
                    "Unexpected exception encountered while writing ser file", ex);
        } finally {
            if (tmpSerFileObjectStream != null) {
                try {
                    tmpSerFileObjectStream.close();
                    if(null!=tmpSerFileStream)tmpSerFileStream.close();
                    if(null!=bufferedStream)bufferedStream.close();
                } catch (IOException ioEx) {
                    logger.warn("Exception caught on trying to close ser file stream", ioEx);
                }
            }
        }
    
    5 回复  |  直到 9 年前
        1
  •  0
  •   Gabriel Jiva    15 年前

    您试图保存的“SiteGroup”对象是什么?我问,因为任何一个对象的大小都不太可能是130MB,除非它有一个巨大的列表/数组/映射/无论其中有什么——如果是这样的话,答案就是将数据保存在数据库中。

    但是,如果对象中没有Monster集合,那么问题很可能是对象树包含对Bagillion对象的引用,而序列化当然会进行深度复制(这个事实已经被用作实现clone()的快捷方式很多次),因此所有内容都会以自上而下的方式一次编目。

    如果这就是问题所在,那么解决方案就是实现您自己的序列化方案,其中每个对象以自下而上的方式进行序列化,可能是在多个文件中,并且只维护对其他对象的引用,而不是整个对象。这将允许您分别写出每个对象,这将产生您正在寻找的效果:由于以块形式写出数据,内存占用会变小。

    然而,实现您自己的序列化(比如实现clone()方法)并不是那么容易。所以这是一个成本/收益的问题。

        2
  •  2
  •   Pat    15 年前

    这在很多层面上都是错误的。这是对序列化的大量滥用。序列化主要用于临时存储对象。例如,

    1. Tomcat服务器之间的会话对象重新启动。
    2. 在JVM之间传输对象(网站上的负载平衡)

    Java的序列化不需要处理对象的长期存储(没有版本控制支持),并且可能无法很好地处理大型对象。

    对于这么大的事情,我建议首先进行一些调查:

    1. 确保您没有尝试持久化整个JVM堆。
    2. 查找可以标记为“transient”的成员变量,以避免将其包含在序列化中(可能您有对服务对象的引用)。
    3. 考虑内存泄漏和对象过大的可能性。

    如果一切都是正确的,那么您必须研究java.io.serialization的替代方案。通过java.io.externalization获得更多的控制可能会起作用。但我建议使用JSON或XML表示。

    更新:

    调查:

    1. google's protocol buffer
    2. facebook's Thrift
    3. Avro
    4. Cisco's Etch

    Take a look at this benchmarkings as well.

        3
  •  0
  •   wolfcastle    15 年前

    听起来,无论您使用的是什么运行时,都有一个不太理想的对象序列化实现,您可能无法控制它。

    这里也提到了类似的投诉,尽管它很古老。 http://objectmix.com/weblogic/523772-outofmemoryerror-adapter.html

    你能使用WebLogic的新版本吗?你能在单元测试中复制这个吗?如果是这样,尝试在不同的JVM下运行它,看看会发生什么。

        4
  •  0
  •   giorgiga    15 年前

    我不知道WebLogic(我想是-jrockit)序列化的具体情况:老实说,我看不出使用bytearrayOutputstreams的理由……

    您可能希望实现 java.io.Externalizable 如果您需要更多的控制如何序列化对象-或切换到完全不同的序列化系统(例如: Terracotta )如果你不想自己写读/写方法(如果你有很多大类)。

        5
  •  0
  •   user207421    9 年前

    为什么它占用所有这些字节作为非同步字节数组输出流?

    这不是默认序列化的工作方式。你必须有一些特殊的代码才能做到这一点。解决方案:不要。