2つの異なるユーザープロセスには、異なる仮想アドレス空間があります。仮想↔物理アドレスのマッピングが異なるため、あるユーザープロセスから別のユーザープロセスにコンテキストを切り替えると、 TLBキャッシュが無効になります。これは非常にコストがかかります。TLBにアドレスがすでにキャッシュされていない場合、メモリアクセスを行うと、障害が発生し、PTEがウォークします。
システムコールには、ユーザー→カーネル、カーネル→ユーザーの2つのコンテキストスイッチが含まれます。これを高速化するために、カーネルで使用するために上位1GBまたは2GBの仮想アドレス空間を予約するのが一般的です。仮想アドレス空間はこれらのコンテキストスイッチ間で変更されないため、TLBフラッシュは必要ありません。これは、各PTEのユーザー/スーパーバイザービットによって有効になります。これにより、カーネルメモリがカーネルスペースにある間だけアクセスできるようになります。ページテーブルが同じであっても、ユーザースペースにはアクセスできません。
2つの別々のTLBのハードウェアサポートがあり、1つはカーネル専用である場合、この最適化はもはや役に立ちません。ただし、専用のスペースが十分にある場合は、TLBを1つ大きくする方がおそらく価値があります。
Linux on x86は、かつて「4G/4Gスプリット」と呼ばれるモードをサポートしていました。このモードでは、ユーザースペースは4GBの仮想アドレス空間全体に完全にアクセスでき、カーネルも4GBの仮想アドレス空間全体に完全にアクセスできます。前述のように、コストは、すべてのsyscallがTLBフラッシュと、ユーザーとカーネルメモリ間でデータをコピーするためのより複雑なルーチンを必要とすることです。これは、最大30%のパフォーマンスペナルティを課すと測定されています。
この質問が最初に尋ねられて答えられてから時代は変わりました:64ビットオペレーティングシステムは今でははるかに普及しています。x86-64の現在のOSでは、 0〜2 47 -1 (0-128TB)の仮想アドレスがユーザープログラムに許可されますが、カーネルは2 47 ×(2 17 -1)〜264-1の仮想アドレス内に永続的に存在します。 (または、アドレスを符号付き整数として扱う場合は、-2 47から-1まで)。
64ビットWindowsで32ビット実行可能ファイルを実行するとどうなりますか?0から232(0-4GB)までのすべての仮想アドレスは簡単に利用できると思いますが、既存のプログラムのバグを公開しないように、32ビット実行可能ファイルはで再コンパイルしない限り0-2GBに制限され/LARGEADDRESSAWARE
ます。その場合は、0〜4GBにアクセスできます。(これは新しいフラグではありません。スイッチで実行されている32ビットWindowsカーネルにも同じことが適用さ/3GB
れ、デフォルトの2G/2Gユーザー/カーネル分割が3G/1Gに変更されましたが、もちろん3〜4GBは範囲外です。 。)
どんな種類のバグがあるのでしょうか?例として、クイックソートを実装していて、2つのポインターがあり、配列の先頭と末尾を指しているとしますa
。b
のピボットとして中央を選択した場合(a+b)/2
、両方のアドレスが2GB未満である限り機能しますが、両方が2GBを超えている場合、加算で整数のオーバーフローが発生し、結果は配列の外になります。(正しい式はa+(b-a)/2
です。)
余談ですが、デフォルトの3G / 1Gユーザー/カーネル分割を使用する32ビットLinuxは、これまで2〜3 GBの範囲にあるスタックでプログラムを実行していたため、このようなプログラミングエラーはすぐに解消される可能性があります。64ビットLinuxは、32ビットプログラムに0〜4GBへのアクセスを提供します。