nbe*_*e11 1 c# memory reflection sos
这个问题主要基于我在此发现的帖子.
我正在尝试使用反射重新创建SOS.dll的一些功能.特别是ObjSize和DumpObject命令.我使用反射来查找所有字段,然后如果字段是基本类型,我将基元类型的大小添加到对象的整体大小.如果字段是值类型,那么我递归调用原始方法并沿着参考树向下走,直到我点击所有基本类型字段.
我一直在使对象大小比SOS.dll ObjSize命令大两倍左右.我发现的一个原因是我的反射代码似乎是在寻找SOS忽略的字段.例如在字典中,SOS找到以下字段:
但是我的反射代码找到了以上所有内容并且还发现:
另外,我对SOS ObjSize和DumpObject命令中发现的不一致感到困惑.我知道DumpObject不会查看引用类型的大小.但是,当我在上面提到的字典上调用对象大小时,我得到:
然后我在Dictionary上调用DumpObject来获取它的引用类型的内存地址.然后,当我调用Objsize的引用类型时,我得到:
顶级字典上的ObjSize不应该大致是字典中所有ObjSizes字段的总和吗?为什么Reflection会发现DumpObject的更多字段?有关为什么我的反射分析返回的数字大于SOS.dll的想法?
另外,我从来没有得到上述链接中提出的一个问题的答案.我在询问是否应该在评估对象的内存大小时忽略属性.普遍的共识是忽视它们.但是,我找到了一个很好的例子,说明属性的支持字段何时不会包含在从Type.GetFields()返回的集合中.在String的引擎盖下查看时,您有以下内容:
Object包含名为FirstChar的属性Object包含属性名为Chars的Object包含属性名为Length的对象包含名为m_stringLength的字段包含名为m_firstChar的字段对象包含名为Empty Object的字段包含名为TrimHead的字段对象包含名为TrimTail的字段对象包含名为TrimBoth的字段对象包含名为charPtrAlignConst的字段对象包含字段名为alignConst的m_firstChar和m_stringLength是属性的支持领域FirstChar,并Length在半焦物业持有,但该字符串的实际内容.这是一个索引属性,可以索引它以返回String中的所有字符,但是我找不到包含字符串字符的相应字段.
有什么想法吗?或者如何获取索引属性的支持字段?索引属性是否应包含在内存大小中?
那么,您的反射代码已被破坏.你提到的4个成员(VersionName等)不是字段,它们是私有常量.我猜你正在使用Type.GetMembers()而不是Type.GetFields()而没有正确检查返回的MemberInfo.MemberType.只需使用GetFields().
请注意,您永远无法获得托管对象的正确大小.对象的布局是不可发现的.大小不是字段的总和,字段是对齐的.非常类似于StructLayout.Pack属性.对齐可以在布局中创建漏洞,即所谓的"填充字节".当类对象存储在数组中时,最后还有额外的填充以使字段对齐.
CLR实际上利用了布局不可发现的事实.如果后面的字段适合两个其他字段之间的填充,它将交换字段.如果您知道对齐规则,则生成比您获得的更小的对象.试图对此进行逆向工程是一项危险的尝试,它还取决于架构(x86 vs x64 vs Arm).
SOS.dll没有这个问题,它可以直接访问CLR为类维护的内部数据.托管代码的限制.
| 归档时间: |
|
| 查看次数: |
511 次 |
| 最近记录: |