0

我们使用 XStream 对 XML 进行序列化/反序列化……结果出现了OutOfMemory 异常。

首先,我不明白为什么我们会收到错误,因为我们有 500MB 分配给服务器。

问题是——我们应该做出哪些改变来避免麻烦?我们希望确保这种实施规模化。

目前我们有大约 60K 个对象,每个对象大约 50 个字节。我们将 60K POJO 加载到内存中,并将它们序列化为一个字符串,我们使用HttpClient. 接收时,我们得到整个String,然后转换成POJO。XML/对象层次结构如下:

<root>
    <meta>
       <date>10/10/2009</date>
       <type>abc</type>
    </meta>

    <data>
        <field>x</field>
    </data>

    [thousands of <data>]
</root>

我认为最好的方法是不要将 POJO 存储在内存中,也不要将内容写入单个字符串。相反,我们应该将各个<data>POJO 写入流。XStream支持这一点,但似乎<meta>不支持该元素。数据需要采用以下形式:

<root> 
    <data>
        <field>x</field>
    </data>

    [thousands of <data>]
</root>

那么什么方法最容易流式传输整个树呢?

4

4 回答 4

3

您肯定希望避免将您的 POJO 序列化为一个巨大的字符串,然后将该字符串写出。使用 XStream API 将 POJO 直接序列化到您的 OutputStream。今年早些时候,当我发现我正在生成 200-300Mb 的 XML 文档并遇到 OutOfMemoryErrors 时,我遇到了同样的情况。进行切换非常容易。

当然,阅读方面也是如此。不要将 XML 读入字符串并要求 XStream 从该字符串反序列化:直接从 InputStream 反序列化。

您提到了关于无法序列化<meta>元素和<data>元素的第二个问题。我不认为这是 XStream 问题或限制,因为我经常按以下顺序序列化更复杂的结构:

<myobject>
    <item>foo</item>
    <anotheritem>foo</anotheritem>
    <alist>
        <alistitem>
            <value1>v1</value1>
            <value2>v2</value2>
            <value3>v3</value3>
            ...
        </alistitem>
        ...
        <alistitem>
            <value1>v1</value1>
            <value2>v2</value2>
            <value3>v3</value3>
            ...
        </alistitem>
    </alist>
    <anotherlist>
        <anotherlistitem>
            <valA>A</valA>
            <valB>B</valB>
            <valC>C</valC>
            ...
        </anotherlistitem>
        ...
    </anotherlist>
</myobject>

我也成功地序列化和反序列化嵌套列表。

于 2009-12-16T04:47:52.370 回答
2

不知道这里的问题是什么......你已经在那个网页上找到了你的答案。

您提供的链接上的示例代码建议:

Writer someWriter = new FileWriter("filename.xml");

ObjectOutputStream out = xstream.createObjectOutputStream(someWriter, "root");
out.writeObject(dataObject);
// iterate over your objects...
out.close();

并用于阅读几乎相同但使用 Reader for Writer 和 Input for Output:

Reader someReader = new FileReader("filename.xml");

ObjectInputStream in = xstream.createObjectInputStream(someReader);
DataObject foo = (DataObject)in.readObject();
// do some stuff here while there's more objects...
in.close();
于 2009-12-16T02:04:20.140 回答
0

我建议使用Visual VMEclipse Memory Analyzer等工具来确保您没有内存泄漏/问题。

另外,你怎么知道每个对象是 50 字节?这听起来不太可能。

于 2009-12-16T01:56:54.883 回答
0

使用 XMLStreamWriter(或 XStream)对其进行序列化,你可以在上面写任何你想要的东西。如果您可以选择获取输入流而不是整个字符串,请使用 SAXParser,它是基于事件的,尽管实现可能有点笨拙,但您将能够读取向您抛出的任何 XML,甚至如果 XML 很大(我用 SAXParser 解析了 2GB 以上的 XML 文件)。

顺便说一句,您应该将二进制数据而不是字符串发送到 XML 解析器。XML 解析器将通过 XML 序列开头的 xml 标记读取接下来要出现的字节数组的编码:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

一个字符串已经被编码了。更好的做法是让 XML 在使用它创建 String 之前解析原始流。

于 2009-12-16T05:13:50.357 回答