久综合色-久综合网-玖草影视-玖草资源在线-亚洲黄色片子-亚洲黄色片在线观看

Hello! 歡迎來到小浪云!


細說|Linux Out Of Memory機制


avatar
小浪云 2025-01-03 138

有時候我們可能會碰到系統中某個進程突然掛掉的情況,查看系統日志后發現是由于系統的 oom(out of memory)機制 觸發導致的。

今天我們來討論一下 OOM機制 是什么,以及如何防止進程因為 OOM機制 而被終止。

什么是OOM機制

OOM 是 Out Of Memory 的縮寫,意味著系統內存不足。OOM機制 是指當系統內存不足時,系統采取的應急措施。

Linux 內核發現系統中的物理內存不足時,首先會嘗試回收可回收內存,主要包括:

  • 用于讀寫文件的頁緩存。
  • 為了性能而延遲釋放的空閑 slab 內存頁。

內核會優先釋放這些內存頁,因為它們的釋放不會影響系統的正常運行,只是為了提升系統性能。

如果釋放這些內存后仍然不足,內核將會采取什么措施呢?它會觸發 OOM killer,殺掉占用內存最多的進程,以釋放更多內存。以下是一個示意圖:

細說|Linux Out Of Memory機制

可以看出,OOM killer 是防止系統崩潰的最后一個手段,不到迫不得已的情況是不會觸發的。

OOM killer 實現

接下來,我們分析一下內核是如何實現 OOM killer 的。

由于在 Linux 系統中,進程申請的都是虛擬內存地址。所以當程序調用 malloc() 申請內存時,如果虛擬內存空間足夠的話,是不會觸發 OOM 機制的。

當進程訪問虛擬內存地址時,如果此虛擬內存地址還沒有映射到物理內存地址的話,那么將會觸發 缺頁異常。

在缺頁異常處理例程中,將會申請新的物理內存頁,并且將進程的虛擬內存地址映射到剛申請的物理內存。

如果在申請物理內存時,系統中的物理內存不足,那么內核將會回收一些能夠被回收的文件頁緩存。如果回收完后,物理內存還是不足的話,那么將會觸發 swapping機制(如果開啟了的話)。

swapping機制 會將某些進程不常用的內存頁寫入到交換區(硬盤分區或文件)中,然后釋放掉這些內存頁,從而達到緩解內存不足的情況。

如果通過上面的手段還不能解決內存不足的情況,那么內核將會調用 pagefault_out_of_memory() 函數來殺掉系統中占用物理內存最多的進程。

我們來看看 pagefault_out_of_memory() 函數的實現:

void?pagefault_out_of_memory(void) { ????... ????out_of_memory(NULL,?0,?0,?NULL,?false); ????... } 

可以看出,pagefault_out_of_memory() 函數最終會調用 out_of_memory() 來殺死系統中占用內存最多的進程。

我們繼續來看看 out_of_memory() 函數的實現:

void?out_of_memory(struct?zonelist?*zonelist,?gfp_t?gfp_mask,?int?order, ???????????????????nodemask_t?*nodemask,?bool?force_kill) { ????...  ????//?1.?從系統中選擇一個最壞(占用內存最多)的進程 ????p?=?select_bad_process(&points,?totalpages,?mpol_mask,?force_kill); ????...  ????//?2.?如果找到最壞的進程,那么調用?oom_kill_process?函數殺掉進程 ????if?(p?!=?(void?*)-1UL)?{ ????????oom_kill_process(p,?gfp_mask,?order,?points,?totalpages,?NULL, ?????????????????????????nodemask,?"Out?of?memory"); ????????killed?=?1; ????} ????... } 

out_of_memory() 函數的邏輯比較簡單,主要完成兩個事情:

  1. 調用 select_bad_process() 函數從系統中選擇一個最壞(占用物理內存最多)的進程。
  2. 如果找到最壞的進程,那么調用 oom_kill_process() 函數將此進程殺掉。

從上面的分析可知,找到最壞的進程是 OOM killer 最為重要的事情。

那么我們來看看 select_bad_process() 函數是怎樣選擇最壞的進程的:

static?struct?task_struct?* select_bad_process(unsigned?int?*ppoints,?unsigned?long?totalpages, ???????????????????const?nodemask_t?*nodemask,?bool?force_kill) { ????struct?task_struct?*g,?*p; ????struct?task_struct?*chosen?=?NULL; ????unsigned?long?chosen_points?=?0; ????...  ????//?1.?遍歷系統中所有的進程和線程 ????for_each_process_thread(g,?p)?{ ????????unsigned?int?points; ????????...  ????????//?2.?計算進程最壞分數值,?選擇分數最大的進程作為殺掉的目標進程 ????????points?=?oom_badness(p,?NULL,?nodemask,?totalpages); ????????if?(!points?||?points?continue; ????????... ????????chosen?=?p; ????????chosen_points?=?points; ????} ????...  ????return?chosen; } 

select_bad_process() 函數的主要工作如下:

  1. 遍歷系統中所有的進程和線程,并且調用 oom_badness() 函數計算進程的最壞分數值。
  2. 選擇最壞分數值最大的進程作為被殺掉的目標進程。

所以,計算進程的最壞分數值就是 OOM killer 的核心工作。我們接著來看看 oom_badness() 函數是怎么計算進程的最壞分數值的:

unsigned?long oom_badness(struct?task_struct?*p,?struct?mem_cgroup?*memcg, ????????????const?nodemask_t?*nodemask,?unsigned?long?totalpages) { ????long?points; ????long?adj;  ????//?1.?如果進程不能被殺掉(init進程和內核進程是不能被殺的) ????if?(oom_unkillable_task(p,?memcg,?nodemask)) ????????return?0; ????...  ????//?2.?我們可以通過?/proc/{pid}/oom_score_adj?文件來設置進程的被殺建議值, ????//????這個值越小,進程被殺的機會越低。如果設置為?-1000?時,進程將被禁止殺掉。 ????adj?=?(long)p->signal->oom_score_adj; ????if?(adj?==?OOM_SCORE_ADJ_MIN)?{ ????????... ????????return?0; ????}  ????//?3.?統計進程使用的物理內存數 ????points?=?get_mm_rss(p->mm) ????????????????+?atomic_long_read(&p->mm->nr_ptes) ????????????????+?get_mm_counter(p->mm,?MM_SWAPENTS); ????...  ????//?4.?加上進程被殺建議值,得出最終的分數值 ????adj?*=?totalpages?/?1000; ????points?+=?adj;  ????return?points?>?0???points?:?1; } 

oom_badness() 函數主要按照以下步驟來計算進程的最壞分數值:

  1. 如果進程不能被殺掉(init進程和內核進程是不能被殺的),那么返回分數值為 0。
  2. 可以通過 /proc/{pid}/oom_score_adj 文件來設置進程的 OOM 建議值(取值范圍為 -1000 ~ 1000)。建議值越小,進程被殺的機會越低。如果將其設置為 -1000 時,進程將被禁止殺掉。
  3. 統計進程使用的物理內存數,包括實際使用的物理內存、頁表占用的物理內存和 swap 機制占用的物理內存。
  4. 最后加上進程的 OOM 建議值,得出最終的分數值。

通過 oom_badness() 函數計算出進程的最壞分數值后,系統就能從中選擇一個分數值最大的進程殺死,從而解決內存不足的情況。

禁止進程被 OOM 殺掉

有時候,我們不希望某些進程被 OOM killer 殺掉。例如 mysql 進程如果被 OOM killer 殺掉的話,那么可能導致數據丟失的情況。

那么如何防止進程被 OOM killer 殺掉呢?從上面的分析可知,在內核計算進程最壞分數值時,會加上進程的 oom_score_adj(OOM建議值)值。如果將此值設置為 -1000 時,那么系統將會禁止 OOM killer 殺死此進程。

例如使用如下命令,將會禁止殺死 PID 為 2000 的進程:

$?echo?-1000?>?/proc/2000/oom_score_adj 

這樣,我們就能防止一些重要的進程被 OOM killer 殺死。

相關閱讀

主站蜘蛛池模板: 看免费人成va视频全 | 亚洲午夜精品一级在线播放放 | 久草在线视频首页 | 女人张开腿让男人添 | 亚洲福利精品一区二区三区 | 亚洲在线影院 | 一级毛片一级毛片a毛片欧美 | 91网在线 | 欧美日本道免费一区二区三区 | 九九久久久久久久爱 | 欧美a级在线 | 特级aaa片毛片免费观看 | 亚洲欧美国产精品久久久 | 黄色美女毛片 | 99国产成人高清在线视频 | 欧美性另类69xxxx极品 | 婷婷亚洲久悠悠色在线播放 | 日韩在线一区二区 | 日韩精品一区二区三区视频网 | 免费高清一级欧美片在线观看 | 亚欧成人毛片一区二区三区四区 | 精品国产成人三级在线观看 | 欧美videos另类齐全 | 精品成人网 | 欧美成人亚洲欧美成人 | 亚洲欧美日本韩国综合在线观看 | 日韩专区亚洲综合久久 | 欧美一级特黄刺激爽大片 | 女性无套免费网站在线看 | 亚洲国产精品久久精品成人 | 在线观看的黄网 | 国产日韩欧美精品 | 荡女妇边被c边呻吟久久 | 国产爽爽视频 | 99视频在线观看视频一区 | 日本a级片免费观看 | 久久有精品 | 午夜在线观看视频免费 成人 | 国产片一级aaa毛片视频 | 欧美一级aⅴ毛片 | 一级大黄美女免费播放 |