個々の型が正しく配置されるように、構造体のメンバー間でパディングが行われることを理解しています。しかし、なぜデータ構造は最大メンバーのアラインメントの倍数でなければならないのでしょうか? 最後にパディングが必要であることを理解していません。
4 に答える
良い質問。この架空のタイプを考えてみましょう。
struct A {
int n;
bool flag;
};
したがって、型のオブジェクトはA
5バイト(intの場合は4バイト、boolの場合は1バイト)かかる必要がありますが、実際には8バイトかかります。なんで?
次のようなタイプを使用すると、答えが表示されます。
const size_t N = 100;
A a[N];
それぞれA
が5バイトしかない場合、a[0]
整列しますがa[1]
、a[2]
他のほとんどの要素は整列しません。
しかし、なぜアライメントが重要なのですか?いくつかの理由がありますが、すべてハードウェアに関連しています。1つの理由は、最近/頻繁に使用されるメモリがCPUシリコンのキャッシュラインにキャッシュされ、迅速にアクセスできることです。キャッシュラインよりも小さい整列されたオブジェクトは常に1行に収まりますが(ただし、以下に追加された興味深いコメントを参照)、整列されていないオブジェクトは2行にまたがり、キャッシュを浪費する可能性があります。
実際には、キャッシュラインとは別に、バイトアドレス可能なデータが32ビットまたは64ビットのデータバスを介して転送される方法に関係する、さらに基本的なハードウェア上の理由があります。ミスアラインメントは、余分なフェッチでバスを詰まらせるだけでなく(以前のようにまたがって)、レジスタが入ってくるときにバイトをシフトするように強制します。さらに悪いことに、ミスアラインメントは最適化ロジックを混乱させる傾向があります(少なくとも、Intelの最適化マニュアルには私にはこの最後の点についての個人的な知識はありませんが、そうです)。したがって、ミスアライメントはパフォーマンスの観点から非常に悪いです。
これらの理由から、通常、パディングバイトを無駄にすることは価値があります。
更新: 以下のコメントはすべて役に立ちます。私はそれらをお勧めします。
ハードウェアによっては、調整が必要な場合や、実行の高速化に役立つ場合があります。
アラインされていないアクセスがハードウェア例外につながる特定の数のプロセッサ(私が信じるARM)があります。簡潔でシンプル。
通常のx86プロセッサの方が寛容ですが、アラインされていない基本型にアクセスする場合は、プロセッサが動作する前にビットをレジスタに取り込むためにより多くの作業を行う必要があるため、ペナルティがあります。それでもパッキングが望ましい場合、コンパイラは通常、特定の属性/プラグマを提供します。
仮想アドレス指定のため。
「...ページをページサイズの境界に揃えると、ハードウェアは、複雑な演算を行うのではなく、アドレスの上位ビットを置き換えることにより、仮想アドレスを物理アドレスにマップできます。」
ちなみに、このウィキペディアのページは非常によく書かれていることがわかりました。
CPUのレジスタサイズが32ビットの場合、単一のアセンブリ命令で32ビット境界にあるメモリを取得できます。32ビットを取得してから、ビット8で始まるバイトを取得するのは時間がかかります。
ところで:パディングする必要はありません。構造物を詰めるように頼むことができます。