質問
確かに、わかりません。1 バイトの長さのメモリワードを持つメモリがあるとします。整列されていないアドレス (つまり、整列されたアドレスの場合のように、4) で割り切れませんか?
他のヒント
最新のプロセッサ上のメモリ サブシステムは、ワード サイズの粒度とアラインメントでのメモリへのアクセスに制限されています。これにはさまざまな理由があります。
スピード
最新のプロセッサには、データをプルする必要がある複数レベルのキャッシュ メモリがあります。シングルバイト読み取りをサポートすると、メモリ サブシステムのスループットが実行ユニットのスループット (別名 CPU バウンド) に厳密に制限されます。これはすべて、その方法を思い出させます PIO モードが DMA に追い抜かれました ハードドライブでも同様の理由が多くあります。
CPU いつも はワード サイズ (32 ビット プロセッサでは 4 バイト) で読み取るため、非境界整列アドレス アクセスをサポートするプロセッサ上で実行すると、プロセッサは複数のワードを読み取ることになります。CPU は、要求されたアドレスにまたがるメモリの各ワードを読み取ります。これにより、要求されたデータにアクセスするために必要なメモリ トランザクション数が最大 2 倍に増加します。
このため、2 バイトの読み取りは 4 バイトの読み取りよりも遅くなる可能性があります。たとえば、メモリ内に次のような構造体があるとします。
struct mystruct {
char c; // one byte
int i; // four bytes
short s; // two bytes
}
32 ビット プロセッサでは、おそらく次のように配置されます。
プロセッサは、これらの各メンバーを 1 つのトランザクションで読み取ることができます。
たとえば、送信効率のためにパックされたネットワークから取得した、パックされたバージョンの構造体があるとします。次のようになります:
最初のバイトの読み取りも同じになります。
プロセッサに 0x0005 から 16 ビットを与えるように要求すると、プロセッサは 0x0004 から 1 ワードを読み取り、1 バイト左にシフトして 16 ビット レジスタに配置する必要があります。多少の追加作業は必要ですが、ほとんどは 1 サイクルで処理できます。
0x0001 から 32 ビットを要求すると、2 倍の増幅が得られます。プロセッサは、0x0000 から結果レジスタに読み取り、1 バイト左にシフトし、次に 0x0004 から一時レジスタに再度読み取り、3 バイト右にシフトし、 OR
それを結果レジスターに合わせます。
範囲
任意のアドレス空間について、アーキテクチャが 2 つの LSB が常に 0 であると想定できる場合 (例: 32 ビット マシン)、4 倍のメモリ (保存された 2 ビットで 4 つの異なる状態を表すことができる)、または同量のメモリにアクセスできます。フラグなどのための 2 ビットのメモリ。アドレスから 2 LSB を取り出すと、4 バイトのアライメントが得られます。とも呼ばれます ストライド 4バイトの。アドレスがインクリメントされるたびに、実質的にビット 0 ではなくビット 2 がインクリメントされます。つまり、最後の 2 ビットは常にインクリメントされ続けます。 00
.
これは、システムの物理設計にさえ影響を与える可能性があります。アドレス バスに必要なビットが 2 つ少ない場合、CPU 上のピンが 2 つ少なくなり、回路基板上のトレースが 2 つ少なくなります。
原子性
CPU はメモリのアライメントされたワードをアトミックに操作できます。これは、他の命令がその操作を中断できないことを意味します。これは、多くのシステムが正しく動作するために重要です。 ロックフリーのデータ構造 その他 同時実行性 パラダイム。
結論
プロセッサのメモリ システムは、ここで説明したものよりもかなり複雑で複雑です。についての議論 x86 プロセッサが実際にメモリをどのようにアドレス指定するか 役に立ちます (多くのプロセッサは同様に動作します)。
メモリの調整を遵守することには、他にも多くの利点があります。以下を参照してください。 このIBMの記事.
コンピュータの主な用途はデータを変換することです。最新のメモリ アーキテクチャとテクノロジは、信頼性の高い方法で、より多くのデータの入出力、およびより高速な実行ユニット間での取得を容易にするために、数十年にわたって最適化されてきました。
ボーナス:キャッシュ
以前に言及したパフォーマンスのためのもう 1 つのアライメントは、(たとえば、一部の CPU 上で) 64B であるキャッシュ ラインでのアライメントです。
キャッシュを活用することでどれだけパフォーマンスが向上するかについて詳しくは、以下をご覧ください。 プロセッサ キャッシュ効果のギャラリー;これから キャッシュラインのサイズに関する質問
キャッシュ ラインを理解することは、特定の種類のプログラムの最適化にとって重要な場合があります。たとえば、データの配置によって、操作が 1 つのキャッシュ ラインにアクセスするか 2 つのキャッシュ ラインにアクセスするかが決定される場合があります。上の例で見たように、これは、位置がずれている場合には、操作が 2 倍遅くなるということを容易に意味します。
あなたは、いくつかのプロセッサを搭載した(のNehalemは行うことができますすることができますこのの)が、以前にバスが64ビット幅であるため、すべてのメモリアクセスは、64ビット(または32ビット)ライン上に整列させた、一度に64ビットを取得しなければならなかった、そしてそれは非常に簡単でした64ビットの整列「チャンク」でこれらをフェッチする
あなたは、単一のバイトを取得したい場合は、だから、あなたは、64ビットのチャンクをフェッチして、あなたはしたくなかったビットをマスクオフ。簡単かつ迅速にあなたのバイトは、右端にあったが、それはその64ビットのチャンクの真ん中にあった場合は、不要なビットをマスクして、適切な場所に介してデータをシフトする必要があると思います。さらに悪いことに、あなたは2バイトの変数を望んでいたが、その場合は、二重に必要なメモリアクセスを必要と、その後、2つのチャンクにまたがって分割されました。
誰もが、メモリは安いと考えているように、は、そう、彼らはただ、コンパイラがそうあなたのコードがより速く、より効率的に無駄なメモリのコストで実行されますサイズプロセッサのチャンク上のデータを揃える作っています。
基本的には、理由がある。
だから、CPUは、多くの場合、これらの日32KBオンチップL1キャッシュの読み出し。しかし、CPUにL1キャッシュを接続するメモリバスは、キャッシュラインサイズの大幅小さい幅を持つことになります。これは、128 のビットの
の順になりますですからます:
262,144 bits - size of memory
128 bits - size of bus
不整列アクセスが時折2本のキャッシュ・ラインを重複し、これは、データを取得するために読み取り全く新しいキャッシュを必要とします。それも、DRAMへのアウトすべての方法を欠場することがあります。
また、CPUの一部は、それぞれがデータの一部を持っているこれら二つの異なるキャッシュ・ラインの外に一緒に単一のオブジェクトを置くために、その頭の上に立つ必要があります。一行に、それは他の、非常に下位ビットに、非常に上位ビットになります。
それはおそらく高速化のためにこれらのトランジスタを使用する方が理にかなっているので、、ハードウェアは完全にCPUのデータバスの必要なビットに整列するオブジェクトを移動ハンドルパイプラインに統合されますが、そのようなハードウェアがずれたオブジェクトのために欠けていることもあり、専用されますアップ正しくプログラムを最適化します。
いずれの場合にも、第二のメモリはそれが時々必要で読み取ることに関係なく専用ハードウェアは(仮にと愚かに)ずれメモリ動作をパッチに捧げられたどのくらいのパイプラインを遅くないだろう。
@joshperryはこの質問への優れた答えを与えています。彼の答えに加えて、私は、特に2倍の増幅を説明したグラフィカルな効果を示し、いくつかの数字を持っています。ここでのどのような効果を示すののGoogleスプレッドシートへのリンクがあります異なるワード整列はのように見えます。 また、ここではテスト用のコードとのGithubの要旨するへのリンクがあります。 テストコードがどの@joshperryジョナサンRentzschによって書か記事から適合されています参照。テストはクアッドコア2.8 GHzのインテルCore i7の64ビットプロセッサと16ギガバイトのRAMを搭載するMacBook Pro上で実行されました。
、それはすべて同じアドレスを読み書きするように配線された4つのバイト幅メモリシステムが効果的に存在することを意味します。整列された32ビットのリードは、すべての4つのメモリシステム内の同じアドレスに格納された情報を必要とするので、すべてのシステムが同時にデータを供給することができます。アラインされていない32ビットのリードは、一つのアドレスからデータを返すために、いくつかのメモリシステムを必要とし、いくつかは、次の上位アドレスからデータを返します。このような要求を満たすことができるように最適化されているいくつかのメモリシステムは、(自分のアドレスに加えて、彼らは効果的には、アドレス指定されたよりも高いものを使うようになり、「プラス1」の信号を持っている)がありますが、このような機能は、かなりのコストを追加しますおよびメモリシステムに複雑。最も汎用メモリシステムは、単に、同時に異なる32ビット・ワードの部分を返すことができません。
は、32ビット・データ・バスを使用している場合、メモリに接続されたアドレスバスのアドレスラインがA 2 から開始され、そうのみ32ビット整列アドレスは、単一のバスサイクルでアクセスすることができます。
ワードアドレスアライメント境界にまたがるので、もし - 16/32ビット・データのために、すなわちA <サブ> 0 サブ>または32ビット・データのための<サブ> 1 サブ>、2つのバス・サイクルがゼロではありませんデータを得るために必要とされています。
いくつかのアーキテクチャ/命令セット非整列アクセスをサポートしていないと、このような試みに例外が発生しますので、コンパイラが生成非整列アクセスコードが作るだけでなく、追加のバス・サイクルが、追加の指示を必要とし、それさえも効率が悪くます。
のPowerPC上では問題なく奇数アドレスから整数を読み込むことができます。
SPARCおよびI86と(私は思う)あなたはこれをしようとするとItatniumは、ハードウェア例外を上げます。
4つの8ビット・ロード対1つの32ビット・ロードは、最新のプロセッサ上の違いの多くを作るつもりイマイチ。データがキャッシュに既に存在するかどうかは、はるかに大きな効果があります。