如何在不实际序列化的情况下估计Java中对象的序列化大小?

要增强群集中的消息传递,重要的是要在运行时了解消息的大小(我应该更喜欢处理本地消息还是远程消息)。

我可以找到基于java检测估计对象内存大小的框架。 我测试了classmexer,它没有接近序列化大小和sourceforge SizeOf。

在一个小的测试用例中,SizeOf错误大约10%,比序列化快10倍。 (仍然瞬态完全打破了估计,因为例如ArrayList是瞬态的,但被序列化为数组,修补SizeOf并不容易。但我可以忍受这种情况)

另一方面,10%的误差和10%的误差似乎不太好。 任何想法我怎么能做得更好?

更新:我还测试了ObjectSize( http://sourceforge.net/projects/objectsize-java )。 结果似乎只适用于非inheritance对象:(

类在运行时获取的大小不一定与它在内存中的大小有关。 您提到的示例是瞬态字段。 其他示例包括对象何时实现Externalizable并自行处理序列化。

如果一个对象实现Externalizable或提供readObject() / writeObject()那么最好的办法是将对象序列化到内存缓冲区以找出大小。 它不会很快,但它会准确。

如果对象使用默认序列化,则可以修改SizeOf以考虑瞬态字段。

序列化许多相同类型的对象后,您可以为该类型构建“序列化配置文件”,将序列化大小与SizeOf的运行时大小相关联。 这样您就可以快速估计序列化大小(使用SizeOf),然后将其与运行时大小相关联,以获得比SizeOf提供的结果更准确的结果。

在其他答案中有许多好处,缺少的一点是序列化机制可能会缓存某些对象

例如,您序列化一系列对象A,B和C,这些对象在每个对象中包含两个对象o1和o2。 让我们说对象开销是100字节,让我们说对象看起来像:

 Object shared = new Object(); Object shread2 = new Object(); A.o1 = new Object() A.o2 = shared B.o1 = shared2 B.o2 = shared C.o1 = shared2 C.o2 = shared 

为简单起见,我们可以说通用对象需要50个字节来序列化,A的序列化大小为100(开销)+ 50(o1)+ 50(o2)= 200个字节。 人们也可以对B和C做出类似的天真估计。 但是,如果在调用reset之前所有三个都被相同的对象输出流序列化,那么你将在流中看到的是A和o1和o2的序列化,然后是b的序列化和o的b, 但是对于o2的引用,因为它是已经序列化的同一个对象 。 因此,假设一个对象引用占用16个字节,B的大小现在为100(开销)+ 50(o1)+ 16(o2的引用)= 166.因此,序列化所需的大小现在已经改变了! 我们可以对C进行同步计算,并且在缓存了两个对象的情况下获得132个字节,因此所有三个对象的序列化大小不同,最大和最小之间的差异为~33%。

因此,除非每次难以准确估计序列化对象所需的大小,否则在没有缓存的情况下序列化整个对象。

只是一个想法 – 您可以先将对象序列化为字节缓冲区,获取其长度,然后决定是将缓冲区内容发送到远程位置还是进行本地处理(如果它取决于消息大小)。

缺点 – 如果以后决定不使用缓冲区,您可能会浪费时间进行序列化。 但是,如果您需要序列化,则估计您会浪费估算工作量(因为在这种情况下,您首先估算并在第二步中序列化)。

无法以精确的速度和速度来估计对象的序列化大小。 例如,一些对象可以是Pi数字的缓存,它们在运行时仅根据您需要的长度构造自身。 因此它只会序列化’length’属性的4个字节,而对象可能会使用数百兆字节的内存来存储该Pi数。

我能想到的唯一解决方案是添加自己的接口,方法是int estimateSerializeSize() 。 对于实现此接口的每个对象,您需要调用此方法以获得正确的大小。 如果某些Object没有实现它 – 你必须使用SizeOf。