WriteObject 没有正确编写 Set?

WriteObject not properly writing a Set?

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

也就是说,我将数据分块到 LinkedHashSet 中,并使用 ObjectOutputStream 菊花通过 GZIpOutputStream 将其写入文件(提及这一点只是为了以防万一)。

现在,当我到达程序的另一端并且 readObject() 我注意到尺寸始终显示为 68,这是第一个尺寸。底层 table 可以多于或少于 68,但 .size() 方法总是 returns 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**
}

而阅读时

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

coordinates.size() 总是 returns 68。现在,我也可以通过 .writeInt() 大小来解决问题,但我只能遍历 68 个成员!

注意 wptSet = new LinkedHashSet<>() 行实际上解决了这个问题。这样做的主要问题是,当在 JVisualVM 中查看程序时,它会使我的堆大小猛增。

更新: 实际上,我只是找到了一个可行的解决方法来修复重新实例化 wptSet 的内存泄漏... System.gc() 在每次调用 .clear() 之后调用它实际上可以避免内存泄漏。

无论哪种方式,我都不必这样做,而且 LinkedHashSet 的发货也不应该表现出这种行为。

好的,我想我明白你的意思了。

这里有一个重现的例子...

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,都会向对象写入一个"shared reference",这样每次反序列化的都是同一个对象。这在 the documentation:

中有解释

Multiple references to a single object are encoded using a reference sharing mechanism so that graphs of objects can be restored to the same shape as when the original was written.

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