2

假设我有一个文件,其中包含很多(很可能是 100K+,可能是数百万)同一类的序列化对象。我阅读了这些对象并用它们做一些事情:

//open stream
try{ 
    while(true) {
        Object o = ois.readObject();
        foo(o);
    }
}catch(EOFException){
}
//close stream...

完成此操作后,已创建了大量令人不安的对象。我的问题是我无法控制这些对象,并且在 GC 决定这样做之前它们不会被释放。

有没有办法对创建的新对象的数量设置上限?例如,如果我的文件有 100K 序列化对象,有没有办法调整 readObject 机制以便使用固定大小的池?

更多细节

~100K 目标文件是许多较小文件的合并结果。这个小过程正在做的是创建一个排序的 csv 文件。

4

5 回答 5

2

到目前为止,任何建议的评论或答案都不起作用(其中大多数也是不必要的),因为它ObjectInputStream本身持有对它曾经反序列化的每个对象的引用,以保存对象图。

您需要限制写入文件的数据量,因此您不必为每个文件处理 100,000 个对象,并且如果可能,您还应该使用ObjectOutputStream.reset()or ObjectOutputStream.writeUnshared(),原因在它们各自的 Javadoc 注释中描述。

于 2013-10-11T06:46:21.993 回答
0

您可以尝试为文件中的每个对象创建一个固定大小的 PhantomReferences 集合。

一旦集合已满,您仅当且仅当可以从 ReferenceQueue 中检索/删除(作为阻塞调用)现有 PhantomReference 时才从文件中读取另一个对象,之后您将其从固定大小的集合中删除并允许另一个被创建。

记得在从 ReferenceQueue 中删除 PhantomReference 后调用“clear()”。

希望这可以帮助!

有关幻影参考的更多信息,请参阅本文档: https ://weblogs.java.net/blog/kcpeppe/archive/2011/09/29/mysterious-phantom-reference

在这里:http: //java.dzone.com/articles/finalization-and-phantom

于 2013-10-11T05:50:43.240 回答
0

如果您必须阅读对象,则必须创建对象,对此您无能为力。更改代码以foo(ois.readObject());向编译器提示它不需要存储引用,但仍会创建对象。

这给你留下了两个选择:

  1. 您相信垃圾收集器是高效且设计良好的。
  2. 您将底层数据结构更改为不存储对象,而是以完全依赖原始数据类型的形式设计它。
于 2013-10-11T23:41:10.137 回答
0

我猜你对编写这些序列化对象的程序的设计也有一些影响。这种问题不是说明Java序列化格式不适合你的问题吗?也许您应该以其他格式写入和读取对象,这允许您在处理流期间将旧对象作为垃圾丢弃?

于 2013-10-11T22:31:47.327 回答
-1

据我了解,EJP 建议使用writeUnshared技术重新生成您的输入文件,而不是writeObject在读取期间使对象可用于 GC。如果是关于重新生成原始内容,那么您是否可以切换到Kryo等其他序列化程序?

Java 的内置序列化速度慢、效率低,并且存在许多众所周知的问题(参见 Effective Java,Josh Bloch 着,第 213 页)。

他们承诺的序列化对象大小比标准 Java 小 5 倍,所以我认为内存消耗应该至少小 5 倍。

编辑

更好的措辞:5x-7x 更重的序列化对象很可能意味着它ObjectInputStream是一个内存消耗者,例如,在工作中使用了太多,尽管最终释放了内存。

于 2013-10-11T21:10:29.467 回答