Swap - ページアウト
Rev.4を表示中。最新版はこちら。
1. ページアウト処理の概要
1.1 ページアウトの開始
空きメモリが少くなってkswapdがwakeupされたり、alloc_pages()でFreeListからページが取れなかった場合、Inactiveリストからページを回収して空きメモリを増やそうとする(「空きページの確保」参照)。Inactiveリストをスキャンした時にPageCacheのページは(Dirtyでなければ)解放されるだけだが、匿名ページは解放前にディスク(スワップファイル)に書き出す必要があり、ページアウト処理が発生する。
Inactiveリストのページをスキャンしてページを解放する処理はshrink_list()で行なわれる。shrink_list()ではページアウトに関して主に以下の処理を行なう。
- ページアウト先の割り当て
- ユーザ空間からのアンマップ
- ページアウト(I/O)
shrink_list()のページアウトに関する処理を抜きだしたものを以下に示す。
while (!list_empty(page_list)) { : /* 匿名ページでSwapCacheに登録されていないければ、 * add_to_swap()を呼び出してページアウト先を決定する。 * 1.2節参照 */ if (PageAnon(page) && !PageSwapCache(page)) { if (!sc->may_swap) goto keep_locked; /* スワップ領域から未使用ページを取得して、SwapCacheに登録 * そして、ページをDirty状態にする */ if (!add_to_swap(page, GFP_ATOMIC)) goto activate_locked; } /* ページがユーザ空間からマップされている * (プロセスのPTEが設定されている)場合は * ユーザ空間からアンマップする。 * 1.3節参照 */ if (page_mapped(page) && mapping) { switch (try_to_unmap(page, 0)) { : : case SWAP_SUCCESS: ; } } /* Dirtyページをディスクに書きだし * 1.4節参照 */ if (PageDirty(page)) { switch(pageout(page, mapping)) { : : case PAGE_SUCCESS: } } }
1.2 ページアウト先の割り当て
shrink_list()でページをスキャンしてSwapCacheに登録されていない匿名ページを見つけたら、このページはページアウト対象なので、まずページアウト先を割り当てるためにadd_to_swap()を呼び出す。
add_to_swap()はSwap空間のどのページにページアウトするかを決定する。その後、ページをSwapCacheに入れてDirty状態にする。
ページアウト先の決定はget_swap_page()で行なう。get_swap_page()は、システムに複数のSwap領域がある場合は以下のルールに基づき、まずどのSwap領域を使用するか決める。
- 空き領域のあるSwap領域の内、最も優先度の高いものを選択する
- 同優先度のSwap領域がある場合は、その中でラウンドロビンで選択する
その次に、選択したSwap領域からscan_swap_map()で空きページを探して返す。scan_swap_map()は空きページを探す際、空きページがある程度連続している領域(クラスタ)を確保して、そこから順番にページを返すようにしている。このようにすることで、複数ページのページアウトが連続ディスクブロックに書き出されやすくなり性能が向上する。
1.3 ページのアンマップ
ページアウトするとページのデータをディスク(スワップファイル)に書き出してページを解放するので、それ以降ページへのアクセスはできなくなる。このため、プロセスのユーザ空間からこのページをマップしていた場合はアンマップする必要がある。
try_to_unmap()は指定ページへのマップをページテーブルから削除する。try_to_unmap()は指定されたページが匿名ページだった場合はtry_to_unmap_anon()を呼び出す。
アンマップ処理の際、ある物理ページにマップしている仮想アドレス空間は1つとは限らない(複数のプロセスで享有されている可能性がある)。このため、try_to_unmap_anon()はRmapをたどり、このページにマップしている全仮想空間からアンマップする。
編集中
PTEにはページアウト先の情報が格納される。