Menu Close
Settings Close

Language and Page Formatting Options

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 の使用

#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>

void *
alloc_workbuf(size_t size)
{
 void *ptr;
 int retval;
 /* 
  * alloc memory aligned to a page, to prevent two mlock() in the
  * same page.
  */
 retval = posix_memalign(&ptr, (size_t) sysconf(_SC_PAGESIZE), size);

 /* return NULL on failure */
 if (retval)
  return NULL;

 /* lock this buffer into RAM */
 if (mlock(ptr, size)) {
  free(ptr);
  return NULL;
 }
 return ptr;
}

void 
free_workbuf(void *ptr, size_t size)
{
 /* unlock the address range */
 munlock(ptr, size);

 /* free the memory */
 free(ptr);
}
この関数 alloc_workbuf はメモリーバッファーを動的に割り当ててロックします。メモリーの割り当ては、メモリー領域をページに合わせるために posix_memalig によって行われます。size 変数が小さい場合は、ページサイズよりも小さいと、通常の malloc 割り当てで残りのページを使用できます。ただし、この手法を安全に使用するために、通常の malloc 割り当てでは mlock 呼び出しを行うことができません。これにより、二重ロック/シングルアンロックの問題が回避されます。この関数 free_workbuf は、メモリー領域のロックを解除し、解放します。
mlock および mlockall の使用方法に加えて、MAP_LOCKED フラグで mmap を使用してメモリー領域の割り当て、ロックすることもできます。以下の例は、mmap を使用した前述のコードの実装です。

例2.3 アプリケーションでの mmap の使用

#include <sys/mman.h>
#include <stdlib.h>

void *
alloc_workbuf(size_t size)
{
 void *ptr;

 ptr = mmap(NULL, size, PROT_READ | PROT_WRITE,
            MAP_PRIVATE | MAP_ANONYMOUS | MAP_LOCKED, -1, 0);

 if (ptr == MAP_FAILED)
  return NULL;

 return ptr;
}

void
free_workbuf(void *ptr, size_t size)
{
 munmap(ptr, size);
}
メモリー 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)