データの配置/パディングが必要な理由を理解しようとしています。ウィキペディアから:
「現代のコンピューターがメモリアドレスから読み書きするとき、ワードサイズのチャンクでこれを行います」
それでも、x86 のmovb
命令を使用して、バイト解像度でデータを明確に移動できます。ここで何が欠けていますか?
データの配置/パディングが必要な理由を理解しようとしています。ウィキペディアから:
「現代のコンピューターがメモリアドレスから読み書きするとき、ワードサイズのチャンクでこれを行います」
それでも、x86 のmovb
命令を使用して、バイト解像度でデータを明確に移動できます。ここで何が欠けていますか?
これはよくある誤解です。 バイト アクセスでは、そのキャッシュ ラインの 32 ビットまたは 64 ビット チャンク(または非キャッシュ アクセス用のメモリ)を含む読み取り-変更-書き込みは必要ありません。最新の x86 ハードウェアは単一バイトをメモリに保存できませんか?を参照してください。.
1 バイト アクセスは、自動的に自然に整列されます。これは、アクセスの幅に合わせて配置されることを意味するため、それ自体よりも広い境界を越えることはありません。
ワードのロードまたはストアは、キャッシュ ラインの境界を越えて分割されない限り、1 つのトランザクションのままです (この場合、CPU は両方のキャッシュ ラインの関連部分に内部的にアクセスする必要があります)。そのため、その見積もりは機械語サイズのアクセスに対してのみ正確です。(Intel の用語では 16 ビットであり、最新の x86 CPU のレジスタまたはバス幅ではないことに注意してくださいword
。前の文で「マシン語」と言ったのはそのためです。)
したがって、C の構造体にパディングが追加されるのは、バイト サイズのフィールドに対してバイト アクセスが非効率的だからではなく、1 バイトよりも広いオブジェクトが自然に整列されるようにするためです(たとえば、構造体int
の a に続くchar
)。
バイト アクセスとは異なり、比較的一般的なプラットフォームの中には、直接の非境界整列アクセスをサポートするものとサポートしないものがあります。C コンパイラは、最も境界整列されたメンバーが何であれ、構造体を境界整列要件があるものとして扱います。たとえば、int
、char
、およびの構造体はdouble
、メンバーのために 64 ビットのアラインメントを持つため、構造体に相対的にアラインするためのdouble
パディングdouble
も絶対的な意味でアラインメントするため、構造体メンバーは常に自然なアラインメントを維持します。
アラインされていないアクセス ペナルティのない架空のプラットフォームでも、アラインされていないオブジェクトがあると、アトミックな読み取りと書き込みに依存するメモリ モデルの実装が非常に複雑になります。多くのプラットフォームでは、アラインされている場合にのみ、これらの操作のアトミック性が保証されるためです。
最新の CPU は、32 ビットまたは 64 ビットのワードだけでなく、キャッシュ ライン サイズのチャンクでデータを転送します。キャッシュできないメモリ領域 (デバイス ドライバのメモリ マップ I/O など) にアクセスしている場合を除き、その場合、実際にはバイト、16 ビット、32 ビット、または 64 ビットのアクセスが外部経由で行われます。バス。
64 ビットの境界を超えない限り、最新の x86 CPU でアラインされていないアクセスによるペナルティはありません。(特に Intel では、キャッシュラインの境界を越えない限り、アライメントされていないロード/ストアに対するペナルティはありません)。
x86_64 でアラインされていないアクセス速度を正確にベンチマークする方法と、 x86タグ wikiのパフォーマンス チューニング リンクも参照してください。
ワード アラインのメモリ アクセスは、バイト アラインのメモリ アクセスよりもはるかに高速です。これにより、大きなデータ ブロックの転送がはるかに高速になります。単一のバイトをアドレス指定できますが、メモリからワードが読み取られ、内部でバイトに縮小される可能性があります。そのため、アクセスが遅くなります。