1

この質問は主に、ここにある私の以前の投稿に基づいています

リフレクションを使用して SOS.dll の機能の一部を再作成しようとしています。具体的にはコマンドObjSizeDumpObjectコマンド。リフレクションを使用してすべてのフィールドを検索し、フィールドがプリミティブ型の場合は、プリミティブ型のサイズをオブジェクト全体のサイズに追加します。フィールドが値型の場合は、元のメソッドを再帰的に呼び出し、すべてのプリミティブ型フィールドに到達するまで参照ツリーをたどります。

オブジェクト サイズが常に SOS.dll ObjSize コマンドよりも 2 倍ほど大きくなっています。私が見つけた理由の 1 つは、リフレクション コードが、SOS が無視しているフィールドを見つけているように見えることです。たとえば、ディクショナリでは、SOS は次のフィールドを検索します。

  • バケツ
  • エントリ
  • カウント
  • バージョン
  • フリーリスト
  • freeCount
  • 比較者
  • キー
  • _syncRoot
  • m_siInfo

ただし、私のリフレクション コードは上記のすべてを検出し、以下も検出します。

  • バージョン名
  • ハッシュサイズ名
  • KeyValuePairsName
  • 比較者名

また、SOS の ObjSize コマンドと DumpObject コマンドで見つかった矛盾についても混乱しています。DumpObject が参照される型のサイズを調べていないことはわかっています。ただし、上記の辞書で Object size を呼び出すと、次のようになります。

  • 辞書 - 532B

次に、Dictionary で DumpObject を呼び出して、その参照型のメモリ アドレスを取得します。次に、参照型で Objsize を呼び出すと、次のようになります。

  • バケット - 40
  • エントリ - 364
  • 比較 - 12
  • キー - 492
  • (残りは null またはプリミティブ)

最上位のディクショナリの ObjSize は、ディクショナリ内のフィールドのすべての ObjSizes のおおよその合計であるべきではありませんか? Reflection が DumpObject よりも多くのフィールドを検出するのはなぜですか? リフレクション分析で SOS.dll よりも大きな数値が返される理由について何か考えはありますか?

また、上記のリンク先のスレッドで尋ねられた質問の 1 つに対する回答も得られませんでした。オブジェクトのメモリ サイズを評価するときに、プロパティを無視する必要があるかどうかを尋ねていました。一般的なコンセンサスは、それらを無視することでした。ただし、プロパティのバッキング フィールドが Type.GetFields() から返されるコレクションに含まれない場合の良い例を見つけました。String のフードの下を見ると、次のようになります。

オブジェクトには、FirstChar という名前のプロパティが含まれています Chars という名前のプロパティが含まれています オブジェクトには、m_stringLength という名前のフィールドが含まれています オブジェクトには、m_firstChar という名前のフィールドが含まれています Empty オブジェクトには、TrimHead という名前のフィールドが含まれていますオブジェクトには alignConst という名前のフィールドが含まれます。m_firstCharとはプロパティのm_stringLengthバッキング フィールドですが、文字列の実際の内容は Chars プロパティに保持されます。これは、文字列内のすべての文字を返すようにインデックス付けできるインデックス付きプロパティですが、文字列の文字を保持する対応するフィールドが見つかりません。FirstCharLength

その理由について何か考えはありますか?または、インデックス付きプロパティのバッキング フィールドを取得する方法は? インデックス付きプロパティをメモリ サイズに含める必要がありますか?

4

1 に答える 1

5

さて、リフレクション コードが壊れています。あなたが言及した4つのメンバー(VersionNameなど)はフィールドではなく、プライベート定数です。Type.GetFields() の代わりに Type.GetMembers() を使用していて、返された MemberInfo.MemberType を適切にチェックしていないと思います。代わりに GetFields() を使用してください。

管理対象オブジェクトの正しいサイズを取得できないことに注意してください。オブジェクトのレイアウトは検出できません。サイズはフィールドの合計ではなく、フィールドは整列されています。StructLayout.Pack プロパティにかなり似ています。アラインメントは、レイアウトに穴、いわゆる「パディング バイト」を作成する可能性があります。クラスオブジェクトが配列に格納されているときにフィールドを整列させるために、最後に余分なパディングがあります。

レイアウトが検出できないという事実は、実際には CLR によって利用されます。後のフィールドが他の 2 つのフィールド間のパディングに収まる場合は、フィールドを交換します。整列規則を知っていた場合に得られるものよりも小さなオブジェクトを生成します。これをリバースエンジニアリングしようとするのは危険な試みであり、アーキテクチャにも依存します (x86 vs x64 vs Arm)。

SOS.dll にはその問題はありません。CLR がクラス用に保持する内部データに直接アクセスできます。マネージ コードへの立ち入り禁止。

于 2013-01-23T18:00:48.023 に答える