我已经对这个主题进行了很多研究,但仍然感到困惑。我之前曾向 stackOverflow 提出过这个问题,但得到的答复并不令人满意。这让我相信这是一个相当高级的话题,需要对 CLR 有深刻的理解才能回答。希望高手能帮帮我。
我正在尝试使用反射重新创建 SOS.dll 的一些功能。特别是ObjSize
andDumpObject
命令。我使用反射来查找所有字段,然后如果这些字段是原始类型,我将原始类型的大小添加到对象的整体大小中。如果该字段是一个值类型,那么我递归地调用原始方法并沿着参考树向下走,直到找到所有原始类型字段。
我一直在获得比SOS.dll ObjSize
命令大两倍左右的对象大小。我发现的一个原因是我的反射代码似乎正在寻找 SOS 忽略的字段。例如在字典中,SOS 查找以下字段:
- 水桶
- 条目
- 数数
- 版本
- 自由清单
- 自由计数
- 比较器
- 钥匙
- 价值观
- _syncRoot
- m_siInfo
但是,我的反射代码找到了以上所有内容,并且还发现:
- 版本名称
- 哈希大小名称
- 键值对名称
- 比较器名称
先前的答案暗示这些是常量而不是字段。常量不是保存在内存中吗?我应该忽略常量吗?我不确定使用哪些绑定标志来获取除常量之外的所有字段......
此外,我对 SOS ObjSize 和 DumpObject 命令中发现的不一致感到困惑。我知道 DumpObject 不会查看引用类型的大小。但是,当我在上面提到的字典上调用对象大小时,我得到:
- 字典 - 532B
然后我在 Dictionary 上调用 DumpObject 来获取它的引用类型的内存地址。然后,当我在它的引用类型上调用 Objsize 时,我得到:
- 水桶 - 40
- 条目 - 364
- 比较器 - 12
- 钥匙 - 492
- (其余为空或原始)
**顶级字典上的 ObjSize 不应该大致是字典内字段上所有 ObjSize 的总和吗?为什么反射会找到更多的 DumpObject 字段?关于为什么我的反射分析返回的数字大于 SOS.dll 的任何想法?**
此外,我在上面链接的主题中提出的一个问题从未得到答案。我在问在评估对象的内存大小时是否应该忽略属性。普遍的共识是忽略它们。但是,我发现了一个很好的示例,说明属性的支持字段何时不会包含在从 Type.GetFields() 返回的集合中。在查看 String 的引擎盖时,您有以下内容:
- 对象包含名为 FirstChar 的属性
- 对象包含名为 Chars 的属性
- 对象包含名为 Length 的属性
- 对象包含名为 m_stringLength 的字段
- 对象包含名为 m_firstChar 的字段
- 对象包含名为 Empty 的字段
- 对象包含名为 TrimHead 的字段
- 对象包含名为 TrimTail 的字段
- 对象包含名为 TrimBoth 的字段
- 对象包含名为 charPtrAlignConst 的字段
- 对象包含名为 alignConst 的字段
m_firstChar 和 m_stringLength 是属性 FirstChar 和 Length 的支持字段,但字符串的实际内容保存在 Chars 属性中。这是一个索引属性,可以对其进行索引以返回字符串中的所有字符,但我找不到保存字符串字符的相应字段。
关于为什么会这样的任何想法?或者如何获取索引属性的支持字段?索引属性是否应该包含在内存大小中?