Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 是否可以控制反序列化文件时创建的对象数量_Java_Performance_Serialization_Garbage Collection_Out Of Memory - Fatal编程技术网

Java 是否可以控制反序列化文件时创建的对象数量

Java 是否可以控制反序列化文件时创建的对象数量,java,performance,serialization,garbage-collection,out-of-memory,Java,Performance,Serialization,Garbage Collection,Out Of Memory,假设我有一个文件,其中包含大量(很可能是100K+,可能是百万)相同类的序列化对象。我阅读这些对象并对其进行处理: //open stream try{ while(true) { Object o = ois.readObject(); foo(o); } }catch(EOFException){ } //close stream... 完成此操作后,会创建大量令人不安的对象。我的问题是,我无法控制这些对象,在GC决定这样做之前,它们不会被

假设我有一个文件,其中包含大量(很可能是100K+,可能是百万)相同类的序列化对象。我阅读这些对象并对其进行处理:

//open stream
try{ 
    while(true) {
        Object o = ois.readObject();
        foo(o);
    }
}catch(EOFException){
}
//close stream...
完成此操作后,会创建大量令人不安的对象。我的问题是,我无法控制这些对象,在GC决定这样做之前,它们不会被释放

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

更多细节
~100K对象文件是许多较小文件的合并结果。这个小流程所做的是创建一个已排序的csv文件。

您可以尝试创建一个固定大小的PhantomReferences集合,从文件中指向每个对象

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

从引用队列中删除PhantomReference后,请记住对其调用“clear()”

希望这有帮助

有关虚拟参考的更多信息,请参阅本文档:

在这里:

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


您需要限制写入文件的数据量,这样就不必为每个文件处理100000个对象,如果可能的话,您还应该使用
ObjectOutputStream.reset()
ObjectOutputStream.writeUnshared()
,原因在各自的Javadoc注释中描述。

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

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

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

编辑


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

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

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

这就给你留下了两个选择:

  • 您相信垃圾收集器是高效且设计良好的
  • 将底层数据结构更改为不存储对象,而是将其设计为完全依赖于基本数据类型的形式

  • 这是你的密码,对吗?计算创建的对象数量,当数量达到100000时停止。尝试查找这些方法writeReplace()和readResolve(),并检查以下链接:@Piro我确实需要这些对象。特别是,foo将它们转换为cvs格式。我需要它们中的每一个,但我无法将它们全部存储在内存中。然后你需要将它们写入一个文件。。。这有点像你开始的地方。readResolve不会有帮助,因为它正在处理创建的对象。我能想到的唯一一件事是不要序列化整个对象,只序列化数据,但它几乎与直接写入csv一样。请您详细说明一下好吗?详细说明什么?为什么ObjectInputStream会无限期地保留引用?因为句柄系统。如果将同一对象序列化两次,而不进行任何reset(),则将序列化第二次出现的句柄,反序列化将生成一个对象和两个引用。这对于在序列化期间保留潜在的循环对象图至关重要,这是对象序列化相对于竞争对手的主要优势之一。要实现这一点,ObjectInputStream必须保留内存,直到它遇到由ObjectOutputStream.reset()生成的流中的重置,然后清除内存。@EJP感谢您的回答。有几个疑问。1) 如果使用writeObject()写入对象,则reset()将仅释放保留内存,对吗?如果使用writeUnshared()编写,则似乎没有必要。2) 是否应该使用
    readUnshared()
    从序列化文件中读取而不保留内存?3) OptionalDataException有什么原因吗?无法确定原因,但它们在阅读时会出现。这一点都不符合。对象仍然是对象。文件中的内容不会保留在内存中,也不会影响内存中对象的大小。是的,结果内存消耗是相同的,因为它在最后被GC释放,但是在中间,负载要高得多。不必要的内存分配必须是为什么内置反序列化比Kryo更重要的因素。“中间的负载要高得多”为什么?你读了一些字节