WriteObject没有正确写一个Set?

时间:2015-04-02 19:53:13

标签: java java-7 objectinputstream objectoutputstream

我希望我没有找到Java中的错误!我正在运行JDK 7u11(主要是因为这是我雇主允许的制裁JVM),我注意到一个非常奇怪的问题。

即,我正在将数据分块到LinkedHashSet并使用ObjectOutputStream通过GZIpOutputStream更改的readObject()雏菊将其写入文件(仅在重要的情况下提及此内容)。

现在,当我到达程序的另一端并.size()时,我注意到大小始终为68,这是我的第一个大小。基础表可以有多于或少于68,但Set方法总是返回68.更麻烦的是,当我尝试手动迭代基础while(...) { oos.writeInt(p_rid); oos.writeObject(wptSet); wptSet.clear(); // wptSet = new LinkedHashSet<>(); // **This somehow causes the heapsize to increase dramatically, but it does solve the problem** } 时,它也会在68处停止。

Set<Coordinate> coordinates = (Set<Coordinate>) ois.readObject();

阅读时

coordinates.size()

.writeInt()总是返回68.现在,我可以通过wptSet = new LinkedHashSet<>()大小来解决方法,但我只能遍历68个成员!

请注意,System.gc()行实际上解决了这个问题。这个问题的主要问题是,当我在JVisualVM中查看程序时,它会使我的heapsize飙升。

更新: 我实际上刚刚找到了一个可行的解决方法来修复重新实例化wptSet的内存泄漏... .clear()在每次调用LinkedHashSet之后调用它实际上会使内存泄漏。

无论哪种方式,我都不应该这样做并且发货{{1}}不应该表现出这种行为。

1 个答案:

答案 0 :(得分:1)

好吧,我想我明白你在问什么。

以下是重现...

的示例
import java.util.*;
import java.io.*;

class Example {
    public static void main(String[] args) throws Exception {
        Set<Object> theSet = new LinkedHashSet<>();
        final int size = 3;

        for(int i = 0; i < size; ++i) {
            theSet.add(i);
        }

        ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
        ObjectOutputStream objectsOut = new ObjectOutputStream(bytesOut);

        for(int i = 0; i < size; ++i) {
            objectsOut.writeObject(theSet);
            theSet.remove(i); // mutate theSet for each write
        }

        ObjectInputStream objectsIn = new ObjectInputStream(
            new ByteArrayInputStream(bytesOut.toByteArray()));

        for(;;) {
            try {
                System.out.println(((Set<?>)objectsIn.readObject()).size());
            } catch(EOFException e) {
                break;
            }
        }
    }
}

输出

3
3
3

这里发生的是ObjectOutputStream每次都检测到你正在写同一个对象。每次写入theSet时,都会有一个&#34;共享参考&#34;写入对象,以便每次反序列化相同的对象。这在the documentation

中有解释
  

使用参考共享机制对单个对象的多个引用进行编码,以便可以将对象图形恢复为与写入原始图像时相同的形状。

在这种情况下,您应该使用writeUnshared(Object)来绕过此机制,而不是writeObject(Object)