2.2. ページ I/O を避けるために mlock を使用
mlock および mlockall システムコールは、指定したメモリー範囲にロックし、そのメモリーをページングできないように指示します。つまり、物理ページがページテーブルエントリーに割り当てられると、そのページへの参照は常に高速になります。
mlock システムコールには、2 つのグループがあります。mlock および munlock は、特定のアドレス範囲のロックおよびロック解除を行います。mlockall および munlockall は、プログラム領域全体をロックまたはアンロックします。
mlock 慎重に検討し、注意して使用してください。アプリケーションが大きい場合や、大規模なデータドメインがある場合は、システムが他のタスクにメモリーを割り当てできない場合に mlock 呼び出しがスラッシュする可能性があります。
注記
mlock は常に注意して使用してください。これを過剰に使用すると、メモリー不足 (OOM) エラーが生じる可能性があります。アプリケーションの先頭には mlockall 呼び出しを付けないでください。アプリケーションのリアルタイム部分のデータとテキストのみがロックされることが推奨されます。
mlock は、このプログラムにページ I/O がないことを保証しません。これは、データがメモリー内に留まるが、同じページに留まることを確認するのに使用されます。move_pages やメモリー圧縮関数は、mlock を使用してもデータを移動できます。
重要
非特権ユーザーは、大きなバッファーで
mlockall または mlock を使用できるようにするために、CAP_IPC_LOCK 機能が必要です。詳細は capabilities(7) man ページを参照してください。
さらに、メモリーロックはページベースで作成され、スタックされないことを通知することが推奨されます。つまり、2 つの動的に割り当てられたメモリーセグメントが、
mlock または mlockall への呼び出し 2 回ロックされた同じページを共有する場合、一致するページの munlock への単一の呼び出し、または munlockall によってアンロックされます。そのため、この二重ロック/シングルロックの問題を防ぐために、アプリケーションがロック解除しているページを認識する必要があります。
double-lock/single-unlock の問題を軽減する最も一般的な 2 つの方法は次のとおりです。
- 割り当て済みおよびロックされたメモリー領域を追跡し、ページをロックする前にラッパー機能を作成すると、そのページにあるユーザー数 (割り当て) を確認します。これは、デバイスドライバーで使用されるリソースカウントの原則です。
- 同じページで二重ロックを防ぐために、ページサイズとアライメントを考慮して割り当てを実行します。
以下のコード例は、2 番目の代替を示しています。
mlock の最適な利用方法は、アプリケーションのニーズとシステムリソースによって異なります。すべてのアプリケーションには単一のソリューションはありませんが、以下のコード例は、メモリーバッファーを割り当て、ロックする関数の実装のスタートポイントとして使用できます。
例2.2 アプリケーションでの mlock の使用
この関数
alloc_workbuf はメモリーバッファーを動的に割り当ててロックします。メモリーの割り当ては、メモリー領域をページに合わせるために posix_memalig によって行われます。size 変数が小さい場合は、ページサイズよりも小さいと、通常の malloc 割り当てで残りのページを使用できます。ただし、この手法を安全に使用するために、通常の malloc 割り当てでは mlock 呼び出しを行うことができません。これにより、二重ロック/シングルアンロックの問題が回避されます。この関数 free_workbuf は、メモリー領域のロックを解除し、解放します。
mlock および mlockall の使用方法に加えて、MAP_LOCKED フラグで mmap を使用してメモリー領域の割り当て、ロックすることもできます。以下の例は、mmap を使用した前述のコードの実装です。
例2.3 アプリケーションでの mmap の使用
メモリー
mmap をページベースで割り当てると、同じページにロックが 2 つ存在せず、二重ロック/シングルアンロックの問題を防ぐのに役立ちます。一方、size 変数がページサイズの倍数ではない場合は、残りのページが無駄になります。さらに、mmap によってロックされたメモリーの munlockall ロックを解除するための呼び出しが必要になります。
フットプリントが小さいアプリケーションのもう 1 つは、コードの時間機密領域を入力する前に、
mlockall を呼び出し、その後に時間機密領域の最後に munlockall を呼び出します。これにより、重要なセクションにおいてページングを減らすことができます。同様に、mlock は比較的静的または、ページ I/O なしでアクセスが必要な徐々に増大するデータリージョンで使用できます。
注記
詳細は、以下の man ページは本セクションに記載の情報に関連しています。
- capabilities(7)
- mlock(2)
- mlock(3)
- mlockall(2)
- mmap(2)
- move_pages(2)
- posix_memalign(3)
- posix_memalign(3p)