- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
这个问题很大程度上是基于我之前找到的帖子 here .
我正在尝试使用反射重新创建 SOS.dll 的一些功能。特别是 ObjSize
和 DumpObject
命令。我使用反射来查找所有字段,然后如果字段是原始类型,我将原始类型的大小添加到对象的整体大小。如果该字段是值类型,那么我将递归调用原始方法并沿着引用树向下走,直到找到所有原始类型字段。
我一直得到比 SOS.dll ObjSize 命令大两倍左右的对象大小。我发现的原因之一是我的反射代码似乎在寻找 SOS 忽略的字段。例如在字典中,SOS 查找以下字段:
但是我的反射代码找到了以上所有内容并且还找到了:
此外,我对在 SOS ObjSize 和 DumpObject 命令中发现的不一致感到困惑。我知道 DumpObject 不会查看引用类型的大小。但是,当我在上面提到的字典上调用对象大小时,我得到:
然后我在 Dictionary 上调用 DumpObject 来获取它的引用类型的内存地址。然后当我在它的引用类型上调用 Objsize 时,我得到:
顶级字典上的 ObjSize 不应该大致是字典内字段上所有 ObjSize 的总和吗?为什么 Reflection 找到的字段比 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 属性(property)中举行。这是一个索引属性,可以对其进行索引以返回字符串中的所有字符,但我找不到包含字符串字符的相应字段。
有什么想法吗?或者如何获取索引属性的支持字段?索引属性是否应包含在内存大小中?
最佳答案
好吧,你的反射代码坏了。您提到的 4 个成员(VersionName 等)不是字段,它们是私有(private)常量。我猜您正在使用 Type.GetMembers() 而不是 Type.GetFields() 并且没有正确检查返回的 MemberInfo.MemberType 。只需使用 GetFields() 即可。
请注意,您永远无法获得托管对象的正确大小。对象的布局是不可发现的。大小不是字段的总和,字段对齐。与 StructLayout.Pack 属性非常相似。对齐会在布局中产生空洞,即所谓的“填充字节”。以及最后的额外填充,以便在类对象存储在数组中时对齐字段。
CLR 实际上利用了布局不可发现的事实。如果后面的字段适合其他两个字段之间的填充,它将交换字段。如果您知道对齐规则,则生成比您得到的对象更小的对象。尝试对此进行逆向工程是一项危险的工作,它还取决于架构(x86 vs x64 vs Arm)。
SOS.dll 没有这个问题,它可以直接访问 CLR 为类维护的内部数据。禁止使用托管代码。
关于c# - SOS.dll ObjSize 和 DumpObject 背后的复杂之处。如何在 C# 中重新创建 SOS.dll?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14483432/
我是一名优秀的程序员,十分优秀!