サブトピックStorage Overhead (on Chapter) - C# 5.0 in a Nutshell book- には、次のような一般的な注意事項があります。
さて、構造体Aのフィールドがスペースの無駄を生成するのはなぜだろうか? または、メモ全体での著者のポイントは何ですか?
各byte
フィールドは 1 バイトを占有し、各long
フィールドは 8 バイトを占有します。これはb
、メモリ内のどこにでも配置できますがl
、8 の倍数のアドレスに配置する必要があることを意味0
しb
ます。したがって、次の使用可能な 8 の倍数に配置する必要があります。つまり、間に8
ある 7 バイトのスペースが無駄になります。
---------------------------------------------------------------------------------
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---------------------------------------------------------------------------------
<--b-> <------------------l-------------------->
<--------------waste------------->
アライメントを見てください。Long は 0、8、16、... の位置にある必要があります。
しかし、最初にバイトがある場合、次のようになります。
b-------llllllll
b はバイト b で、l は長い l です。- は「無駄なスペース」です。ご覧のとおり、構造体は16バイト全体を使用していますが、9バイトしか使用されていないため、7バイトが無駄になっています
構造体のこのデフォルトには 2 つの理由があります。
1)他の人がすでに説明したように、パフォーマンス。フィールド メンバーをそのサイズの倍数で配置すると、転送が高速になります。
2) ほとんどの C/C++ コンパイラのデフォルトと同じにする。これにより、C/C++ (すべての Windows API を含む) との相互運用が少し簡単になります。
構造をマーシャリングする必要がない場合は、次を使用できることに注意してください[StructLayout(LayoutKind.Auto)]
。
[StructLayout(LayoutKind.Auto)]
struct A
{
byte b;
long l;
}
ということで、以下のコード
unsafe
{
Console.WriteLine(sizeof(A));
}
12
より良いパッキングを示します。
使用すれば[StructLayout(LayoutKind.Sequential, Pack = 1)]
、サイズを に下げることができます9
。
これらは通常、プロセッサのワード境界に配置されているため、それらを取得するのは簡単な 1 サイクルの操作です。それ以外の場合、CLR はアドレス全体を取得し、構造体フィールドを XOR/シフトして参照する必要があります。