5

ヒープ上のかなり深いオブジェクト グラフの対話型ビューを表示できるようにするだけでなく、多くの統計情報を取得しようとしているマネージド プロセスの非常に大きなメモリ ダンプがいくつかあります。SOS を使用した WinDbg の set に相当するものを考えてみて!do <address>くださいprefer_dml 1。プロパティを継続的にクリックしてその値を確認できますが、多くのオブジェクトを比較するためのはるかに使いやすい UI でのみ可能です。

Microsoft.Diagnostics.Runtime (ClrMD) がこのタスクに特に適していることがわかりましたが、配列フィールドの操作に苦労しており、オブジェクト フィールドについて少し混乱しています。より良い。


Array : ヒープから直接アドレスを指定して配列をターゲットにして使用するClrType.GetArrayLengthClrType.GetArrayElementValue問題なく動作しますが、別のオブジェクトのフィールドを掘り下げるとClrInstanceField.GetValueClrInstanceField.ElementTypeClrElementType.SZArray(オブジェクト グラフを掘り下げることはArrayまだありませんが、同様に処理したいと考えています)。

編集:ClrType for使用しSystem.UInt64て配列フィールドを逆参照するparent address + offset of the array fieldた (配列ポインターが格納されているアドレスを計算するために使用します)。その後、EnumerateObjects から取得した場合と同じように操作できます。プロパティをサポートしていない一部の配列で問題が発生していArrayComponentTypeます。私はまだ構造体の配列でテストしていないので、それがインライン構造体のCスタイルの割り当てにint[]なるのか、それともヒープ上の構造体へのポインターの配列になるのか疑問に思っています. Guid[]からの取得に問題があるタイプの1つですArrayComponentType

オブジェクト:修正 (論理エラー) まず、呼び出した後、問題なく使用できるアドレス (?)が返されるので、ネストされたオブジェクトのフィールド名と値を確認できます。とはいえ、ポリモーフィズムを考慮する必要があるため、同じアドレスで使用しようとしたところ、NULL または完全に間違ったものが返されました。最初のユース ケースではアドレスが機能するのに、2 番目のユース ケースでは機能しないのは奇妙に思えます。ClrInstanceFieldTypeClrElementType.ObjectGetFieldValueulongClrInstanceField.Type.FieldsClrHeap.GetObjectType

String : Fixed (回避策が見つかりました) 私の実際のプロジェクトでは既に SOS 付きの DbgEng を使用しているため、アドレスによって文字列の値を簡単に取得する別の方法がありますが、使用しようとしてClrInstanceField.GetFieldValue文字列を返すことに成功したのは非常に奇妙に思えましたが、完全に不正確な結果 (奇妙な文字の束)。多分私はこれを間違っていますか?


編集:元のコードから LINQPad で実行される抽象化を抽出しました。ここに投稿するには少し長くなりますが、要点はすべてここにあります。コピー/貼り付け/リファクタリングのすべてからまだ少し面倒です。これらの問題を修正した後、最終的なソースを CodePlex または GitHub に投稿する可能性があります。

コード ベースはかなり大きく、プロジェクトに固有のものですが、どうしても必要な場合は、サンプル セットを抽出できる場合があります。つまり、ClrMD オブジェクトへのすべてのアクセスは非常に単純です。!dumpheap -stat(ルート オブジェクトに対しては正常に機能する) などのSOS コマンドから初期アドレスを取得し、ClrHeap.GetTypeByNameorを使用しますClrHeap.GetObjectType。その後は、メンバー、、およびClrType.Fieldsのみに依存します。ClrInstanceFieldTypeElementTypeGetFieldValue

おまけとして、NuGet パッケージで提供される XML ドキュメントのブラウザー フレンドリーバージョンを見つけましたが、これは IntelliSense が提供するドキュメントと同じものです。

4

1 に答える 1

4

コードがどのように見えるかを確認せずに非常に正確に答えるのは難しいでしょうが、基本的には次のようになります。

GetFieldAddress/GetFieldValue を呼び出せるようにするために最初に知っておく必要があるのは、オブジェクト アドレスが通常のポインターか内部ポインターかということです。つまり、ヒープ上のオブジェクト、または実際のオブジェクト内の内部構造を直接指している場合 (実際のオブジェクト内の String フィールドと Struct フィールドを考えてみてください)。

GetFieldAddress/GetFieldValue から間違った値を取得している場合は、通常、内部ポインターがあることを指定していないことを意味します (または、ないのにあると思っていました)。

2 番目の部分は、値の意味を理解することです。

field.IsPrimitive() が true の場合: GetFieldValue() は実際のプリミティブ値 (つまり、Int32、Byte など) を取得します。

field.IsValueClass() が true の場合、GetFieldAddress() は構造体への内部ポインターを取得します。したがって、そのアドレスで使用する GetFieldAddress/Value() の呼び出しは、内部ポインターであることを伝える必要があります。

field.ElementType が ClrElementType.String の場合、GetFieldValue を呼び出して実際の文字列の内容を取得する必要があることを覚えているようです (確認する必要がありますが、これである必要があります)。

それ以外の場合は、オブジェクト参照があり、その場合、GetFieldValue() は新しい参照オブジェクトへの通常のポインターを取得します。

これは理にかなっていますか?

于 2014-03-06T15:57:17.347 に答える