在java序列化期间可以缓冲对象吗?

时间:2010-07-01 09:56:23

标签: java serialization

我有一个非常大的对象,我希望序列化。在序列化过程中,它占用了大约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 个答案:

答案 0 :(得分:2)

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

  1. tomcat服务器重启之间的会话对象。
  2. 在jvms之间传输对象(在网站上进行负载平衡)
  3. Java的序列化不会处理对象的长期存储(没有版本控制支持),也可能无法很好地处理大对象。

    对于那么大的东西,我会先建议一些调查:

    1. 确保您没有尝试保留整个JVM堆。
    2. 查找可以标记为“瞬态”的成员变量,以避免将它们包含在序列化中(可能是您对服务对象的引用)
    3. 考虑存在内存泄漏且对象过大的可能性。
    4. 如果一切都是正确的,你将不得不研究java.io.Serialization的替代方案。通过java.io.Externalization进行更多控制可能会有效。但我建议像json或xml表示。

      更新:

      调查:

      1. google's protocol buffer
      2. facebook's Thrift
      3. Avro
      4. Cisco's Etch
      5. Take a look at this benchmarkings as well.

答案 1 :(得分:0)

  

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

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

答案 2 :(得分:0)

听起来你正在使用的运行时具有一个不太理想的对象序列化实现,你可能无法控制。

这里提到类似的抱怨,虽然它已经很老了。 http://objectmix.com/weblogic/523772-outofmemoryerror-adapter.html

您可以使用较新版本的weblogic吗?你能在单元测试中重现这个吗?如果是这样,请尝试在不同的JVM下运行它,看看会发生什么。

答案 3 :(得分:0)

我不知道weblogic(即我认为是JRockit)特别是序列化:说实话,我认为没有理由使用ByteArrayOutputStreams ......

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

答案 4 :(得分:0)

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

但是如果对象中没有怪物集合,那么问题可能是对象树包含对bagillion对象的引用,并且序列化当然会进行深层复制(这个事实已被用作实现克隆的快捷方式()很多次),所以一切都以自上而下的方式一次性编目。

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

但是,实现自己的序列化(如实现clone()方法)并不是那么容易。所以这是一个成本/收益的事情。