オブジェクトがラージ オブジェクト ヒープ(85,000 バイトを超える) に到達するオブジェクトの数を確認するために、オブジェクトがどれだけのメモリを必要とするかを調べようとしています。
int の場合は 4、long の場合は 8、各オブジェクトの参照型などの場合は 4 (または 64 ビットの場合は 8) を追加するのと同じくらい簡単ですか、それともメソッド、プロパティなどのオーバーヘッドがありますか?
オブジェクトがラージ オブジェクト ヒープ(85,000 バイトを超える) に到達するオブジェクトの数を確認するために、オブジェクトがどれだけのメモリを必要とするかを調べようとしています。
int の場合は 4、long の場合は 8、各オブジェクトの参照型などの場合は 4 (または 64 ビットの場合は 8) を追加するのと同じくらい簡単ですか、それともメソッド、プロパティなどのオーバーヘッドがありますか?
実際のオブジェクトのサイズには、それが参照するオブジェクトのサイズは含まれないことを忘れないでください。
最終的に大きなオブジェクト ヒープになる可能性が高いのは、配列と文字列だけです。その他のオブジェクトは、それ自体が比較的小さい傾向があります。(たとえば) 10 個の参照型変数 (x86 ではそれぞれ 4 バイト) と 10 個の GUID (それぞれ 16 バイト) を持つオブジェクトでさえ、約 208 バイトしか占有しません (型参照と同期ブロックには多少のオーバーヘッドがあります)。
同様に、配列のサイズについて考えるときは、要素の型が参照型の場合、配列自体にカウントされるのは参照のサイズだけであることを忘れないでください。つまり、20,000 個の要素を持つ配列を取得したとしても、配列オブジェクト自体のサイズは (x86 上で) 80K をわずかに超える程度に過ぎず、さらに多くのデータを参照していても問題ありません。
オブジェクトのサイズを取得するには、次の手順に従ってください。
VisualStudio2010の[プロジェクトのプロパティ]→[デバッグ]タブ→[アンマネージコードのデバッグを有効にする]に移動します。
VisualStudioの[デバッグ]メニュー→ [オプションと設定] → [デバッグ] → [記号]に移動します。
そこで、Microsoft Symbol Serverを有効にし、デフォルトのままにします(シンボルがダウンロードを開始する場合があります)。
コードにブレークポイントを設定し、デバッグを開始します(F5)。
デバッグ→ウィンドウ→イミディエイトウィンドウを開きます。
入力.load sos.dll
(ストライキの息子)
!DumpHeap -type MyClass
(サイズを調べたいオブジェクト)を入力します
出力から、オブジェクトのアドレス、つまり(00a8197c)を見つけます。
アドレスMTサイズ00a8197c0095512436
次、!ObjSize 00a8197c
そこに行きます→sizeof(00a8197c)= 12(0x48)バイト(MyClass)
高度な .NET デバッグの領域に入ります。John Robins のデバッグ本から始めてください。
Sos.dll (.NET ディストリビューションの一部) およびSosex.dll拡張で WinDBG を使用します。これらのツールを使用すると、アプリケーションの実行中に何が起こっているかを実際に確認できます。上記の質問に対する答えが見つかります。
(別の推奨事項は、内部で何が起こっているかを確認するために、 Shared Source CLI 2.0、別名 Rotor 2をインストールすることです。)
簡素化されたゴメスの方法:
Visual Studio (2010) プロジェクトのプロパティ* → [デバッグ] タブ → [アンマネージ コードのデバッグを有効にする] に移動します。
コードにブレークポイントを設定し、デバッグを開始します ( F5)。
Debug → Windows → Immediate Windowを開きます。
入る.load sos
Enter (myObject をオブジェクトの名前に置き換えます)
? String.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc( myObject ).GetHandleValue()).ToString())
結果をパラメータとして使用します!ObjSize
参照: SOS.DLL、オブジェクト アドレス、および Visual Studio デバッガー
例 ( という名前のオブジェクトを探していますtbl
):
.load sos
extension C:\Windows\Microsoft.NET\Framework\v4.0.30319\sos.dll loaded
? string.Format("{0:x}",Integer.Parse(System.Runtime.InteropServices.GCHandle.InternalAddrOfPinnedObject(System.Runtime.InteropServices.GCHandle.Alloc(tbl).GetHandleValue()).ToString())-4)
"27ccb18"
!ObjSize 27ccb18
PDB symbol for clr.dll not loaded
sizeof(027ccb18) = 154504 ( 0x25b88) bytes (System.Data.DataTable)
巨大な値型またはインスタンス型 (つまり、何千ものフィールド) でない限り、心配する必要がある型は、大きな配列または文字列だけです。もちろん、配列のサイズを把握するには、要素のサイズを知る必要があります。
.NET (現在) は、ネイティブ コンパイラが型を整列するのとほぼ同じ方法で型を整列します。基本型には、通常、それらのサイズに最も近い 2 の整数乗を切り上げた自然な配置があります。
Single, Int32, UInt32 - 4
IntPtr, UIntPtr, pointers, references - 4 on 32-bit, 8 on 64-bit
Double, Int64, UInt64 - 8
Char, Int16, UInt16 - 2
Byte, SByte - 1
型をアセンブルするとき、明示的なレイアウトが使用されていないと仮定すると、コンパイラは、特定の型のすべてのフィールドが、その型に一致する境界に位置合わせされたインスタンス内の開始オフセットを持つことを確認します。
ユーザー定義型自体にはアラインメントがあり、フィールド型の中で最高のアラインメントとして計算されます。必要に応じて、型のサイズも調整するために型のサイズが拡張されます。
ただし、もちろん、すべての参照型はサイズと配置が IntPtr.Size のみであるため、参照型のサイズはその型の配列には影響しません。
CLR は、独自の裁量で、上記とは異なる型のレイアウトを選択する可能性があることに注意してください。これは、キャッシュの局所性を高めたり、配置に必要なパディングを減らしたりするためです。