C/C++では、次のようにpoint
という名前の単純な構造体を定義するとします。
struct test
{
double height;
int age;
char gender;
}
この構造体の特定のインスタンスについては、test A
はA.height, A.age, A.gender
メモリ内で隣接していますか?
より一般的には、配列の構造と構造の配列のメモリ内のレイアウトはどのように見えますか?写真は本当に役に立ちます。
それらは必ずしもメモリ内で連続しているとは限りません。これは struct padding が原因です。
ただし、特定のケースでは、連続している可能性があります。しかし、次のような順序に変更した場合:
struct test
{
char gender;
int age;
double height;
}
そうなると、おそらくそうならないでしょう。ただし、特定のケースでは、構造体を8バイトに再調整するために、gender
の後にパディングが発生する可能性があります。
SoA(Struct of Arrays)とAoS(Array of Structs)は次のようになります。
SoA:
-----------------------------------------------------------------------------------
| double | double | double | *pad* | int | int | int | *pad* | char | char | char |
-----------------------------------------------------------------------------------
AoS:
-----------------------------------------------------------------------------------
| double | int | char | *pad* | double | int | char | *pad* | double | int | char |
-----------------------------------------------------------------------------------
各構造体内のAoSパッドに注意してください。一方、SoAはアレイ間をパディングします。
これらには次のトレードオフがあります:
個々のフィールドは、それらの間に他の変数が格納されないという意味で隣接しています。また、宣言した順序で格納されることが保証されています。ただし、コンパイラは個々のフィールドの間にパディングを挿入して、たとえばWordの境界に合わせて自由に配置できます。したがって、次のようになります。
struct test
{
double height;
char gender;
int age;
};
メモリ内では次のようになります。
+7 +6 +5 +4 +3 +2 +1 +0
+---+---+---+---+---+---+---+---+
0x0000 | height |
+---+---+---+---+---+---+---+---+
0x0008 | age | |gen|
+---+---+---+---+---+---+---+---+
SoAとAoSの違いについては、想像どおりにレイアウトされています。
「お使いのプラットフォーム、コンパイラ、blahblahblahに依存します」という標準の免責事項を除いて...はい、height
、age
、およびgender
はメモリ内で連続しない間のパディング:
height|age|gender
ただし、test
の配列がある場合、次の要素のgender
が適切に配置されるように、各配列要素は各height
の後にそれらの間にパディングがあります。
|height0|age0|gender0|padding0|height1|age1|gender1|padding1|...
可能な限り少ないメモリ量を使用することが目標である場合は、パディングを使用しないため、「配列の構造」を使用する必要があります。
|height0|height1|...
|age0|age1|...
|gender0|gender1|...