10

メモリを消費するアプリケーションの最適化に取り組んでいます。それに関連して、C# 参照型のサイズのオーバーヘッドについて質問があります。

C# オブジェクトは、そのフィールドと同じバイト数を消費し、加えて管理オーバーヘッドがいくらか追加されます。管理オーバーヘッドは、.NET のバージョンと実装によって異なる可能性があると思います。

C# オブジェクト (C# 4.0 および Windows 7 および 8 環境)の管理オーバーヘッドのサイズ (オーバーヘッドが可変の場合は最大サイズ) を知っていますか?

管理オーバーヘッドは 32 ビットと 64 ビットの .NET ランタイムで異なりますか?

4

3 に答える 3

16

通常、GCによって割り当てられたオブジェクトごとに8バイトまたは12バイトのオーバーヘッドがあります。32ビットランタイムではsyncblk用に4バイト、タイプハンドル用に4バイト、64ビットランタイムでは8バイトがあります。詳細については、「. NET Framework Internalsへのドリルイン」の「ObjectInstance」セクションを参照して、MSDNMagazineでCLRがランタイムオブジェクトを作成する方法を確認してください。

実際の参照は、32ビットまたは64ビットの.NETランタイムでも変更されることに注意してください。

また、アドレスの境界に収まるように型にパディングがある場合がありますが、これは問題の型に大きく依存します。これにより、オブジェクト間に「空のスペース」が発生する可能性もありますが、データがいつどのように整列されるかを決定するのは実行時(ほとんどの場合、StructLayoutAttributeで影響を与えることができます)次第です。

于 2013-01-11T20:58:04.283 に答える
7

「The Truth About .NET Objects And Sharing They Between AppDomains」というタイトルの記事がオンラインにあり、いくつかのローター ソース コードと、オブジェクトを実験し、プレーン ポインターを介してアプリ ドメイン間でそれらを共有した結果が示されています。

http://geekswithblogs.net/akraus1/archive/2012/07/25/150301.aspx

  • CLR のすべての 32 ビット バージョンで 12 バイト
  • CLR のすべての 64 ビット バージョンで 24 バイト

何百万ものオブジェクト (N) を配列に追加することで、これを非常に簡単にテストできます。ポインターのサイズはわかっているため、値を N で割ることでオブジェクトのサイズを計算できます。

var initial = GC.GetTotalMemory(true);
const int N = 10 * 1000 * 1000;
var arr = new object[N];
for (int i = 0; i < N; i++)
{
    arr[i] = new object();
}

var ObjSize = (initial - GC.GetTotalMemory(false) - N * IntPtr.Size) / N;

.NET プラットフォームでのおおよその値を取得します。

オブジェクト サイズは実際には、GC が最小オブジェクト サイズについて推測できるように定義されています。

\sscli20\clr\src\vm\object.h

//
// The generational GC requires that every object be at least 12 bytes
// in size.   
#define MIN_OBJECT_SIZE     (2*sizeof(BYTE*) + sizeof(ObjHeader))

たとえば 32 ビットの場合、これはオブジェクトの最小サイズが 12 バイトであることを意味し、4 バイトの穴が残ります。空のオブジェクトの場合、この穴は空ですが、たとえば int を空のクラスに追加すると、穴が埋められ、オブジェクトのサイズは 12 バイトのままになります。

于 2013-01-11T21:40:32.000 に答える
4

オブジェクトのオーバーヘッドには次の2つのタイプがあります。

  • オブジェクトの処理に使用される内部データ。
  • データメンバー間のパディング。

内部データは2つのポインターであるため、32ビットアプリケーションでは8バイト、64ビットアプリケーションでは16バイトです。

データメンバーは、アドレス境界が均等になるようにパディングされます。たとえば、クラスにabyteとaがある場合、次のマシンワード境界で開始するように、おそらく3つの未使用バイトが埋め込まれます。intbyteint

クラスのレイアウトは、システムのアーキテクチャに応じてJITコンパイラによって決定されるため(フレームワークのバージョンによって異なる場合があります)、C#コンパイラには認識されません。

于 2013-01-11T20:58:54.887 に答える