如何在Java中估计对象的序列化大小而不实际序列化它们?

2022-09-03 07:10:13

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

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

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

另一方面,10%的错误速度提高了10倍似乎不是很好。任何想法,我怎么能做得更好?

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


答案 1

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

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

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

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


答案 2

其他答案中有很多优点,缺少的一件事是序列化机制可能会缓存某些对象

例如,序列化一系列对象 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进行类似的天真估计。但是,如果在重置之前,所有这三个都由相同的对象输出流序列化,那么您将在流中看到A,o1和o2的序列化,然后是B和o1的序列化,但是对o2的引用,因为它是已经序列化的同一对象。因此,假设对象引用需要 16 个字节,B 的大小现在是 100(开销)+ 50 (o1) + 16(o2 的引用)= 166。因此,序列化所需的大小现在已经发生了变化!我们可以对 C 进行模拟计算,并在缓存两个对象的情况下获得 132 个字节,因此所有三个对象的序列化大小都不同,最大和最小之间的差异约为 33%。

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