Linuxカーネルに関する技術情報を集めていくプロジェクトです。現在、Linuxカーネル2.6解読室の第2章までを公開中。
下記do_try_to_free_pages関数は、ユーザメモリ、バッファキャッシュなどをを検索し、利用頻度度の低いものからどんどん解放する。目的の解放数が達成できるまでの間、何度も繰り返す。
解放するとはいっても、v2.2の時とは異なりv2.4では、好きなときにいつでも解放可能なキャッシュ(INACTIVE-CLEANリストにリンクされたページ)まで落すのみで、完全なフリーページにすることはない。(そのページ上のデータと全く同じものがディスク上にも存在する状態であるため、いつそのページが別の用途に転用されても問題が生じない)
ページ解放は二段階で行われる。
do_try_to_free_pages() if(空きメモリが不足) { 解放候補のページ(INACTIVE_DIRTYリスト上のページ)を いつでも解放可能なページ(INACIVE_CLEANリスト上の ページにする(page_launder関数) } if(空きメモリが不足 || 解放候補のページが少なめ) { ディレクトリエントリキャッシュの解放(shrink_dcache_memory関数) iノードキャッシュの解放(shrink_icache_memory関数) 利用中(ACTIVE)のメモリの解放を試みる(refill_inactive関数) } else { カーネル内メモリアロケータ内の解放可能な メモリを解放する(kmem_cache_reap関数) }
page_lander関数はその関数名の示すとおり、解放候補のページの洗濯をし、いつでも解放可能な綺麗な状態にする。いつでも解放可能な状態にするだけで、本当のフリーページに戻すようなことはしない。
page_launder() for(解放候補リストinactive_dirty) { if (最近参照されたページ) { ページをACTIVE状態にする(active_listに繋ぐ) continue } if (I/O中なら) { inactive_dirtyリストに繋ぎ直す continue } if (バッファ域、バッファ域にマップされたページキャッシュ) { バッファ域の解放(try_to_free_buffers関数) if(解放できなかったなら) { (I/O中の場合、まだDirtyな場合など) inactive_dirtyリストに繋ぎ直す } else if(複数のところから参照されている) ACTIVE状態にする(active_listに繋ぐ) else /* ページキャッシュなら */ inactive_cleanリストに繋ぐ } else if (ページキャッシュ) { inactive_cleanリストに繋ぐ } else { ACTIVE状態にする(active_listに繋ぐ) } if(最初なら) { バッファのフラッシュ(wakeup_bdflush関数) } }
解放候補とできるページ量が少なくなってくるとrefill_inactive関数にて、解放候補のページを作り出す。
プロセスページのスワップへの追い出し(swap_out関数)より、キャッシュ域の解放(refill_inactive_scan関数)を優先的に行う。
refill_inactive() カーネル内メモリアロケータ内の解放可能な メモリを解放する(kmem_cache_reap関数) for(プライオリティを変更しつつ) { /*swapアウトによる空きメモリの生成*/ while (refill_inactive_scan() || swap_out()) { if(目的のページ数を解放したら) return } ディレクトリエントリキャッシュの解放(shrink_dcache_memory関数) iノードキャッシュの解放(shrink_icache_memory関数) /*共有メモリのスワップアウト*/ while (shm_swap()) { if(目的のページ数を解放したら) return } if(空きメモリ量が十分になった) return }
ページが最近参照されたかどうかを示すためにpage構造体中に参照ビット(PG_referenced)を持っており、これらキャッシュを参照する度(find_page_nolock関数)にこのビットを立てるようにしている。refill_inactive_clean関数では、この参照ビットが立っているページはAGE(参照頻度)を最大にし解放の対象外とする。また同時に参照ビットのクリアを行う。
refill_inactive_scan関数は、参照されていない(各種キャッシュ用の)ページであれば、解放候補リスト(INACTIVEリストに繋ぎ直す)
refill_inactive_scan() for(ACTIVEリスト上のページ) { if(ページに参照ビットPG_referencedが立っていたら) { ページの参照ビットPG_referencedを落す ページのAGEを元に戻す(age_page_up_nolock関数) } else { ページのAGINGを行う(age_page_down_ageonly関数) if(何処からも参照あれていないページ) ページを解放対象ページとする(deactivate_page_nolock関数) } if(1ページ解放指定 && 解放成功) return; }
(NIS)HirokazuTakahashi
2000年12月09日 (土) 23時55分06秒 JST1
[PageInfo]
LastUpdate: 2008-08-27 14:18:05, ModifiedBy: hiromichi-m
[Permissions]
view:all, edit:login users, delete/config:members