在.NET中确定复杂对象的大小的方法?

18

在.NET中,有没有办法确定复杂对象的总大小?该对象由其他对象组成,可能引用其他复杂对象。该对象所封装的一些对象可能是POD,而其他对象可能不是。


1
这些对象是否可序列化? - user287466
可能是 :) 对于我的含糊不清,我尽量让这个问题尽可能地通用化。 - Polaris878
在C#/.NET上下文中,“POD”是什么?这是一个C++术语... - Pavel Minaev
@Pavel,是的,POD是C++术语...我使用POD来指代int、string、float、double等等...基本上是.NET的POD类型...值类型 :) - Polaris878
我认为你所指的最合适的CLR术语是“可平坦化类型”,这包括所有基元类型(不包括对象引用)和结构体,其中所有字段本身都是可平坦化类型。 - Pavel Minaev
C# 版本的 POD 不应该被称为简单类型吗?顺便说一下,如果有人和我一样从未听说过 POD,它代表着“普通旧数据”。 - Chad Levy
5个回答

10
你拥有的不是“复杂对象”,而是一个对象图。要确定其总大小,您需要遍历该图-从某个根对象开始,并使用反射枚举引用类型的字段并检索其值(当然还要检查循环引用)。
要获取图中特定对象的大小,请参见这个相关问题的答案,但请注意这是一种邪恶的黑科技,完全不受支持,可能会损坏(甚至可能已经损坏),并可能导致在天堂领域发生大规模的小猫灭绝。 话虽如此,由于这是一个实现细节,你本应该没有理由去精确地获取它,因此也没有什么“非黑科技”可以获取精确值。而对于调试/分析应用程序内存使用情况的目的,这种黑科技已经足够了。

谢谢 Pavel。我在提问时已经了解到了复杂性,只是好奇是否有人已经创建了一个计算这个的对象图遍历 :) - Polaris878

4
简单来说,没有办法知道对象的大小。假设所有的对象都是可序列化的,你可以使用BinaryFormatter将它们序列化为二进制块,然后读取其大小。但是,这会包括一些元数据,并使实际对象大小膨胀(但这是一个合理的估计)。
对于值类型,您可以使用Marshal.SizeOf(),但它不考虑任何子对象。它会将任何内部引用类型计算为指向它的指针的大小。
反射是另一种方法,但不会显示占用内存的任何私有成员。所以,除非我错了,否则没有真正正确的方法来做到这一点。

2

棘手的问题...

如果两个对象指向同一个字符串变量,那么哪一个“拥有”这个字符串?听起来你需要模拟垃圾回收才能得到真正的答案。并不是很轻量级。


2
@Paul:不变性与此有什么关系?重点是对象可能会持有从外部给予它的字符串引用(例如文件名)。那个字符串是否“属于”该对象?它应该计入对象的大小还是不计入? - Pavel Minaev

1

此前在StackOverflow的其他地方已经回答过:

在C#中查找对象实例的字节数大小

您需要引入不安全代码(由于需要指针操作)- 代码如下:

static unsafe int CalcSize(object obj)
{
    RuntimeTypeHandle th = obj.GetType().TypeHandle;
    int size = *(*(int**)&th + 1);
    return size;
}

还要记得将项目设置(项目->构建选项卡)标记为“允许不安全代码”。

1

试一下 System.Runtime.InteropServices.Marshal.SizeOf()


Marshal.SizeOf() 无法考虑子对象的大小。 - drharris
请记住,这是一个安全关键功能,因此不幸的是,在许多情况下无法正常工作。 - Matt Greer
1
它提供了对象的编组表示的大小,但这并不完全相同。 - Pavel Minaev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接