第2章 メモリーの割り当て

Linux ベースのオペレーティングシステムは、仮想メモリーシステムを使用します。ユーザー空間アプリケーションによって参照されるアドレスは、物理アドレスに変換する必要があります。これは、基盤となるコンピューターシステムのページテーブルとアドレス変換ハードウェアの組み合わせにより実行されます。
プログラムと実際のメモリー間の翻訳メカニズムを持つことの 1 つの結果として、オペレーティングシステムが必要なときにページを奪うことができることがあります。これは、以前使用されていたページテーブルエントリーを無効なとマークすることで実現されます。そのため、通常のメモリー不足でも、オペレーティングシステムがあるアプリケーションからページをスケートして別のアプリケーションに渡す可能性があります。これは、決定論的な動作を必要とするシステムに悪影響を与える可能性があります。ページフォールトがトリガーされるため、通常、固定時間で実行される命令は通常よりも時間がかかる可能性があります。

2.1. 需要ページング

Linux では、プログラムによって生成されたすべてのメモリーアドレスは、プロセッサーのアドレス変換メカニズムを通過します。アドレスは、プロセス固有の仮想アドレスから物理メモリーアドレスに変換されます。これは 仮想メモリー と呼ばれます。
Red Hat Enterprise Linux for Real Time 仮想メモリーシステムの概要

図2.1 Red Hat Enterprise Linux for Real Time 仮想メモリーシステム

翻訳メカニズムの 2 つの主要コンポーネントは、ページテーブル翻訳ルックアップバッファー (TLB) です。ページテーブルは、物理メモリーの仮想メモリーから物理メモリーへのマッピングを含むマルチレベルテーブルです。これらのマッピングは、プロセッサーの仮想メモリー変換ハードウェアにより読み取り可能です。TLB は、ページテーブル変換のキャッシュです。
ページテーブルエントリーに物理アドレスが割り当てられている場合は、常駐の作業セット と呼ばれます。オペレーティングシステムが他のプロセスのメモリーを解放する必要がある場合、作業セットからページを削除できます。これが発生すると、そのページ内の仮想アドレスへの参照によりページフォールトが作成され、ページが再割り当てされます。システムの物理メモリーが非常に少ない場合、このプロセスは thrash を開始し、そのプロセスから常にページを奪うようになり、プロセスを完了できなくなります。仮想メモリーの統計は、/proc/vmstat ファイルの pgfault 値を検索することで監視できます。
TLB は、仮想メモリー変換のハードウェアキャッシュです。TLB を持つプロセッサーコアはいずれも並行して TLB をチェックし、ページテーブルエントリーのメモリー読み取りを開始します。仮想アドレスの TLB エントリーが有効であれば、メモリー読み取りが中止され、TLB の値がアドレス変換に使用されます。
TLB は 参照のローカリティーの 原則で動作します。つまり、コードが (ループやコール関連の関数など) 長い期間メモリー領域内に留まる場合、TLB 参照はアドレス変換のメインメモリーを回避します。これにより、処理時間が大幅に短縮されます。決定論的および高速コードを記述する場合は、参照のローカリティーを維持する関数を使用します。これは、再帰ではなくループを使用することを意味します。再帰を避けられない場合は、関数の最後に再帰呼び出しを配置します。これは tail-recursion と呼ばれ、これは比較的小さいメモリー領域でコードが機能し、メインメモリーからのテーブル変換の取得を回避します。
メモリーレイテンシーの潜在的なソースは、マイナーページフォールトと 呼ばれます。それらは初期化される前に、プロセスがメモリーの一部にアクセスしようとすると作成されます。この場合、システムは、メモリーマップやその他の管理構造を埋める操作をいくつか実行する必要があります。マイナーページフォールトの重大度は、システムの負荷およびその他の要因に依存できますが、通常は短く、影響を及ぼす影響があります。
より深刻なメモリーレイテンシーは、主要なページ障害 です。これは、システムがディスクとメモリーバッファーを同期したり、他のプロセスに属するメモリーページをスワップしたり、その他の入出力アクティビティーを取得してメモリーを解放する必要がある場合に発生する可能性があります。これは、プロセッサーが、プロセッサーに物理ページが割り当てられていない仮想メモリーアドレスを参照すると発生します。空のページを参照すると、プロセッサーがフォールトを実行し、カーネルコードにページの割り当てと戻りを指示します。これにより、すべてレイテンシーが大幅に向上します。
マルチスレッドアプリケーションを作成する場合、データの破損を設計する際にマシントポロジーを考慮することが重要です。トポロジーはメモリー階層であり、CPU キャッシュと NUMA ノードが含まれます。データ情報を異なるキャッシュや NUMA ドメインの CPU で非常に密接に共有すると、トラフィックの問題やボトルネックが生じる可能性があります。
競合により、パフォーマンスに深刻な問題が生じる可能性があります。ハードウェアによっては、さまざまなメモリーバスのトラフィックはいかなる規則にも適用されません。これを回避するために、必ず使用しているハードウェアを確認してください。
メモリー割り当てエラーは、CPU のアフィニティー、スケジューリングポリシー、および優先順位を使用して常に除外することはできません。アプリケーションがパフォーマンス低下を表示する場合は、ページフォールトによる影響を受けているかどうかを確認する利点があります。これには複数の方法がありますが、簡単な方法は /proc ディレクトリー内のプロセス情報を確認することです。特定のプロセス PID については、cat コマンドを使用して /proc/PID/stat ファイルを表示します。このファイル内の関連するエントリーは以下のとおりです。
  • Field 2: 実行ファイルのファイル名
  • Field 10: マイナーページフォールトの数
  • Field 12: メジャーページフォールトの数
プロセスがページに遭遇すると、カーネルが障害を処理するまですべてのスレッドがフリーズします。この問題を解決する方法はいくつかありますが、ページ障害を回避するためにソースコードを調整することが最善の方法になります。

例2.1 /proc/PID/stat ファイルを使用したページ障害の確認

この例では、/proc/PID/stat ファイルを使用して、実行中のプロセスでページ障害の有無を確認します。
cat コマンドとパイプ関数を使用して、/proc/PID/stat ファイルの 2 行目、10 行目、および 12 行のみを返します。
~]# cat /proc/3366/stat | cut -d\ -f2,10,12
(bash) 5389 0
上記の出力では、PID 3366 が bash で、マイナーページフォールトが 5389 件報告され、主要なページフォールトはありません。

注記

詳細情報や参照文書は、以下の文書が、このセクションの情報に関連しています。
  • Linux System Programming』 by Robert Love