1

私はこのトピックについて多くの調査を行ってきましたが、まだ困惑しています。以前、stackOverflow にこの質問をしたことがありますが、満足のいく回答は得られませんでした。このことから、これはかなり高度なトピックであり、答えるには CLR の深い理解が必要であると私は信じています。教祖が私を助けてくれることを願っています。

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

リフレクションを使用して 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 という名前のプロパティが含まれています
  • オブジェクトには、Length という名前のプロパティが含まれています
  • オブジェクトには、m_stringLength という名前のフィールドが含まれています
  • オブジェクトには、m_firstChar という名前のフィールドが含まれています
  • オブジェクトには、Empty という名前のフィールドが含まれています
  • オブジェクトには、TrimHead という名前のフィールドが含まれています
  • オブジェクトには TrimTail という名前のフィールドが含まれています
  • オブジェクトには、TrimBoth という名前のフィールドが含まれています
  • オブジェクトには charPtrAlignConst という名前のフィールドが含まれています
  • オブジェクトには、alignConst という名前のフィールドが含まれています

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

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

4

1 に答える 1

2

このアイデアは興味深いものですが、Reflection はオブジェクトの実際のストレージへのアクセスを提供しないため、最終的には無駄だと思います。リフレクションでは型をクエリできますが、実際のメモリ表現 (CLR の実装の詳細) はできません。

参照型の場合、CLR 自体が各インスタンス (MT および syncblk) に内部フィールドを追加します。これらは、Reflection API によって表示されません。さらに、CLR は、型の定義に応じて、フィールドのストレージに任意の種類のパディング/圧縮を使用する場合があります。これが意味することは、プリミティブ型のサイズが異なる参照型間で一貫していない可能性があるということです。リフレクションでも、これを発見することはできません。

つまり、Reflection は、正しい結果を生成するために必要な多くの詳細を検出できません。

于 2013-01-30T16:51:03.430 に答える