吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

OOM Killer機(jī)制學(xué)習(xí)

馬哥Linux運(yùn)維 ? 來(lái)源:馬哥Linux運(yùn)維 ? 作者:馬哥Linux運(yùn)維 ? 2022-12-19 16:17 ? 次閱讀

當(dāng)系統(tǒng)內(nèi)存不足以分配時(shí),Linux內(nèi)核會(huì)使用一種OOM Killer(Out-Of-Memory Killer)機(jī)制釋放內(nèi)存,該機(jī)制通過(guò)一系列比較選擇出最適合的進(jìn)程并將其kill掉,從而達(dá)到保障系統(tǒng)穩(wěn)定運(yùn)行的目的。那么在內(nèi)核中,OOM Killer具體是怎么運(yùn)轉(zhuǎn)的呢?

一、觸發(fā)過(guò)程

在申請(qǐng)內(nèi)存時(shí),必然會(huì)調(diào)用alloc_page(),在__alloc_pages中有以下調(diào)用關(guān)系:

17124298-7df8-11ed-8abf-dac502259ad0.png

其中,在__alloc_pages_slowpath中,當(dāng)反復(fù)嘗試reclaim和compact后仍不成功,就會(huì)調(diào)用__alloc_pages_may_oom進(jìn)行內(nèi)存釋放。

/*
*Ifwefailedtomakeanyprogressreclaiming,thenweare
*runningoutofoptionsandhavetoconsidergoingOOM
*/
if(!did_some_progress){
if(oom_gfp_allowed(gfp_mask)){
if(oom_killer_disabled)
gotonopage;
/*Coredumpscanquicklydepleteallmemoryreserves*/
if((current->flags&PF_DUMPCORE)&&
!(gfp_mask&__GFP_NOFAIL))
gotonopage;
page=__alloc_pages_may_oom(gfp_mask,order,
zonelist,high_zoneidx,
nodemask,preferred_zone,
classzone_idx,migratetype);
......
}

如果定義了oom_killer_disabled,就會(huì)直接goto到nopage,不會(huì)觸發(fā)OOM機(jī)制(此值默認(rèn)為0).

二、工作過(guò)程(基于Linux-3.18)

當(dāng)內(nèi)核檢測(cè)到內(nèi)存不足,執(zhí)行到out_of_memory時(shí),OOM Killer會(huì)選擇一個(gè)進(jìn)程并把他kill掉:

p = select_bad_process(&points, totalpages, mpol_mask, force_kill);

具體的選擇過(guò)程在select_bad_process中進(jìn)行:

/*
*Simpleselectionloop.Wechosetheprocesswiththehighest
*numberof'points'.Returns-1onscanabort.
*
*(notdocbooked,wedon'twantthisoneclutteringupthemanual)
*/
staticstructtask_struct*select_bad_process(unsignedint*ppoints,
unsignedlongtotalpages,constnodemask_t*nodemask,
boolforce_kill)
{
structtask_struct*g,*p;
structtask_struct*chosen=NULL;
unsignedlongchosen_points=0;

rcu_read_lock();
for_each_process_thread(g,p){
unsignedintpoints;

switch(oom_scan_process_thread(p,totalpages,nodemask,
force_kill)){
caseOOM_SCAN_SELECT:
chosen=p;
chosen_points=ULONG_MAX;
/*fallthrough*/
caseOOM_SCAN_CONTINUE:
continue;
caseOOM_SCAN_ABORT:
rcu_read_unlock();
return(structtask_struct*)(-1UL);
caseOOM_SCAN_OK:
break;
};
points=oom_badness(p,NULL,nodemask,totalpages);
if(!points||points

select_bad_process會(huì)選擇一個(gè)points數(shù)值最高的進(jìn)程并返回。在宏for_each_process_thread循環(huán)里,通過(guò)switch和oom_scan_process_thread對(duì)一些進(jìn)程做特殊化處理,如一些進(jìn)程不適合被結(jié)束,就跳過(guò)本次循環(huán)。如果該進(jìn)程沒(méi)有特殊狀態(tài),oom_scan_process_thread返回OOM_SCAN_OK,繼續(xù)向下進(jìn)行判斷。這里使用了oom_badness對(duì)其points值進(jìn)行計(jì)算。

/**
*oom_badness-heuristicfunctiontodeterminewhichcandidatetasktokill
*@p:taskstructofwhichtaskweshouldcalculate
*@totalpages:totalpresentRAMallowedforpageallocation
*
*Theheuristicfordeterminingwhichtasktokillismadetobeassimpleand
*predictableaspossible.Thegoalistoreturnthehighestvalueforthe
*taskconsumingthemostmemorytoavoidsubsequentoomfailures.
*/
unsignedlongoom_badness(structtask_struct*p,structmem_cgroup*memcg,
constnodemask_t*nodemask,unsignedlongtotalpages)
{
longpoints;
longadj;

if(oom_unkillable_task(p,memcg,nodemask))
return0;

p=find_lock_task_mm(p);
if(!p)
return0;

adj=(long)p->signal->oom_score_adj;
if(adj==OOM_SCORE_ADJ_MIN){
task_unlock(p);
return0;
}

/*
*ThebaselineforthebadnessscoreistheproportionofRAMthateach
*task'srss,pagetableandswapspaceuse.
*/
points=get_mm_rss(p->mm)+atomic_long_read(&p->mm->nr_ptes)+
get_mm_counter(p->mm,MM_SWAPENTS);
task_unlock(p);

/*
*Rootprocessesget3%bonus,justlikethe__vm_enough_memory()
*implementationusedbyLSMs.
*/
if(has_capability_noaudit(p,CAP_SYS_ADMIN))
points-=(points*3)/100;

/*Normalizetooom_score_adjunits*/
adj*=totalpages/1000;
points+=adj;

/*
*Neverreturn0foraneligibletaskregardlessoftherootbonusand
*oom_score_adj(oom_score_adjcan'tbeOOM_SCORE_ADJ_MINhere).
*/
returnpoints>0?points:1;
}

在oom_badness的上半部分,對(duì)進(jìn)程做了一些判斷,排除了不可進(jìn)行kill的進(jìn)程以及oom_score_adj為OOM_SCORE_ADJ_MIN(-1000)的進(jìn)程,進(jìn)行了return 0。接著是進(jìn)行比重計(jì)算,將rss、nr_ptes、swap空間使用量占RAM比重相加。如果是Root進(jìn)程則去掉3%的比重points -= (points * 3) / 100;。之后對(duì)adj進(jìn)行歸一化并與points相加,在返回值計(jì)算時(shí),使用了一個(gè)三目運(yùn)算符,即當(dāng)points大于0時(shí),返回points,否則返回1。這里注釋給出的原因是,對(duì)于有資格的進(jìn)程(即可以被OOM Killer掉的進(jìn)程),是絕不能返回0的。(這里我的理解是,如果points返回0,這個(gè)進(jìn)程可能在之后的比較中就處于劣勢(shì),成為漏網(wǎng)之魚(yú))

17269194-7df8-11ed-8abf-dac502259ad0.png

再回到select_bad_process中看,之后跟的一個(gè)if比較就是為了進(jìn)行取最大值的判斷,再之后判斷該進(jìn)程是否為thread_group_leader,若是則continue跳過(guò)本次循環(huán),否則該進(jìn)程就是被chosen的進(jìn)程。

再回到out_of_memory中,得到p值后,需要對(duì)其進(jìn)行判斷:

if(!p){
dump_header(NULL,gfp_mask,order,NULL,mpol_mask);
panic("Outofmemoryandnokillableprocesses...
");
}
if(p!=(void*)-1UL){
oom_kill_process(p,gfp_mask,order,points,totalpages,NULL,
nodemask,"Outofmemory");
killed=1;
}

當(dāng)p是0時(shí),即沒(méi)有找到可以kill掉的進(jìn)程,內(nèi)核發(fā)出一個(gè)panic。當(dāng)p不是0時(shí),即找到了可以kill掉的進(jìn)程,則通過(guò)oom_kill_process將其kill。

在oom_kill_process中有個(gè)“有意思”的事是,在kill之前,會(huì)先遍歷其子進(jìn)程,重新通過(guò)oom_badness計(jì)算出一個(gè)最適合被kill掉的子進(jìn)程,該子進(jìn)程會(huì)有限考慮被kill掉,從而避免kill父進(jìn)程導(dǎo)致的接管子進(jìn)程的工作開(kāi)銷(xiāo)。并且最終被kill掉的進(jìn)程的名字叫victim,這個(gè)單詞的中文含義是犧牲者,有點(diǎn)是為了整個(gè)系統(tǒng)的穩(wěn)定運(yùn)轉(zhuǎn)而犧牲的意思。在這之后OOM Killer會(huì)kill掉和victim使用相同虛擬內(nèi)存的進(jìn)程,并通過(guò)發(fā)送SIGKILL信號(hào)將其終止。

1764f574-7df8-11ed-8abf-dac502259ad0.png

三、到底為什么會(huì)發(fā)生Out Of Memory?

因?yàn)槲锢韮?nèi)存頁(yè)的分配發(fā)生在使用的瞬間而非分配的瞬間。若某個(gè)進(jìn)程申請(qǐng)了200MB內(nèi)存,但實(shí)際上只使用了100MB,未使用到的100MB根本沒(méi)有分配物理內(nèi)存頁(yè)。當(dāng)進(jìn)程需要內(nèi)存時(shí),進(jìn)程從內(nèi)核得到的只是虛擬地址的使用權(quán),而不是實(shí)際的物理地址,實(shí)際的物理內(nèi)存只有當(dāng)進(jìn)程真的去訪(fǎng)問(wèn)新獲取的虛擬地址時(shí),產(chǎn)生缺頁(yè)異常,從而進(jìn)入分配實(shí)際物理地址的過(guò)程,之后系統(tǒng)返回產(chǎn)生異常的地址,重新執(zhí)行內(nèi)存訪(fǎng)問(wèn)。虛擬內(nèi)存需要物理內(nèi)存作為支撐,當(dāng)分配了太多虛擬內(nèi)存,導(dǎo)致物理內(nèi)存不夠時(shí),就發(fā)生了Out Of Memory。這種允許超額commit的機(jī)制就是overcommit。

overcommit即操作系統(tǒng)在應(yīng)用申請(qǐng)內(nèi)存空間時(shí)不去檢查是否超出當(dāng)前可用量,隨意滿(mǎn)足申請(qǐng)要求,應(yīng)用也不管實(shí)際是否有足夠多的內(nèi)存可使用,認(rèn)為我申請(qǐng)了2G,OS肯定就給我2G使用。最后,隨著內(nèi)存越用越多,OS發(fā)現(xiàn)內(nèi)存不夠用了,必須要收回一些內(nèi)存才行,就觸發(fā)了上述的OOM Killer機(jī)制回收內(nèi)存。

Linux根據(jù)參數(shù) vm.overcommit_memory設(shè)置overcommit:

0 ——默認(rèn)值,啟發(fā)式overcommit,它允許overcommit,但太明顯的overcommit會(huì)被拒絕,比如malloc一次性申請(qǐng)的內(nèi)存大小就超過(guò)了系統(tǒng)總內(nèi)存。

1 ——Always overcommit. 允許overcommit,對(duì)內(nèi)存申請(qǐng)來(lái)者不拒。

2 ——不允許overcommit,提交給系統(tǒng)的總地址空間大小不允許超過(guò)CommitLimit。(CommitLimit 就是overcommit的閾值,申請(qǐng)的內(nèi)存總數(shù)超過(guò)CommitLimit的話(huà)就算是overcommit)

四、總結(jié)

由于物理內(nèi)存的分配機(jī)制,以及overcommit的存在,導(dǎo)致了在物理內(nèi)存不夠時(shí)的OOM Killer。OOM Killer機(jī)制很有意思,它為了保護(hù)整個(gè)系統(tǒng)的安全穩(wěn)定運(yùn)行,需要找出一個(gè)最合適的進(jìn)程kill掉。這是不得已而為之,內(nèi)核必須在kill掉進(jìn)程和系統(tǒng)崩潰之間選擇其中一個(gè)。內(nèi)核代碼中out_of_memory注釋中也體現(xiàn)了這種無(wú)奈。> * If we run out of memory, we have the choice between either

killing a random task (bad), letting the system crash (worse)

OR try to be smart about which process to kill. Note that we

don't have to be perfect here, we just have to be good.

在選擇合適的進(jìn)程時(shí),OOM Killer會(huì)挑選一個(gè)占用內(nèi)存最大的進(jìn)程,這也很好理解,畢竟kill掉一個(gè)大的可以獲得更多的物理內(nèi)存,并且損失也比較小。如果kill掉多個(gè)小的,損失會(huì)比較大。Linux內(nèi)核總是去選擇更高效的方法。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 內(nèi)核
    +關(guān)注

    關(guān)注

    3

    文章

    1382

    瀏覽量

    40425
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11345

    瀏覽量

    210400
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    3055

    瀏覽量

    74331

原文標(biāo)題:OOM Killer機(jī)制學(xué)習(xí)

文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    容器JVM內(nèi)存配置最佳實(shí)踐

    Killer機(jī)制,此時(shí)系統(tǒng)會(huì)終止內(nèi)存占用較多的進(jìn)程以保證系統(tǒng)的正常運(yùn)行。特別是在容器環(huán)境下,不合理的JVM堆參數(shù)設(shè)置會(huì)導(dǎo)致各種異常現(xiàn)象產(chǎn)生,例如應(yīng)用堆大小還未到達(dá)JVM設(shè)置的堆閾值或應(yīng)用的規(guī)格限制,就因?yàn)?b class='flag-5'>OOM導(dǎo)致重啟等。
    發(fā)表于 06-20 09:45 ?933次閱讀
    容器JVM內(nèi)存配置最佳實(shí)踐

    STM32MP157D提示DAC沒(méi)有進(jìn)入syspend,導(dǎo)致休眠失敗怎么解決?

    sync: 0.023 seconds Freezing user space processes ... (elapsed 0.002 seconds) done. OOM killer
    發(fā)表于 05-30 08:16

    ESP8266真的是Arduino Killer

    一大早起來(lái)看見(jiàn)篇文章,標(biāo)題好驚悚[ Meet the Arduino Killer: ESP8266]人家剛要相親相愛(ài),你們標(biāo)題party就冒出來(lái)寫(xiě)killer這么嚇人的文章,真的好么?
    發(fā)表于 08-20 06:50

    linux內(nèi)核oom機(jī)制分析

    Linux 內(nèi)核有個(gè)機(jī)制OOM killer(Out-Of-Memory killer),該機(jī)制會(huì)監(jiān)控那些占用內(nèi)存過(guò)大,尤其是瞬間很快消耗
    發(fā)表于 11-13 17:01 ?1367次閱讀
    linux內(nèi)核<b class='flag-5'>oom</b><b class='flag-5'>機(jī)制</b>分析

    基于非聯(lián)合型學(xué)習(xí)機(jī)制學(xué)習(xí)神經(jīng)元模型

    針對(duì)生物神經(jīng)細(xì)胞所具有的非聯(lián)合型學(xué)習(xí)機(jī)制,設(shè)計(jì)了具有非聯(lián)合型學(xué)習(xí)機(jī)制的新型神經(jīng)元模型學(xué)習(xí)神經(jīng)元。首先,研究了非聯(lián)合型學(xué)習(xí)機(jī)制中習(xí)慣化學(xué)習(xí)機(jī)制
    發(fā)表于 11-29 10:52 ?0次下載
    基于非聯(lián)合型<b class='flag-5'>學(xué)習(xí)機(jī)制</b>的<b class='flag-5'>學(xué)習(xí)</b>神經(jīng)元模型

    如何制作USB Killer

    注意:使用此USB Killer會(huì)損壞您的設(shè)備,請(qǐng)自行使用風(fēng)險(xiǎn)。
    的頭像 發(fā)表于 11-15 17:01 ?7864次閱讀

    一個(gè)線(xiàn)上服務(wù)OOM的問(wèn)題分享

    大家都知道,如果出現(xiàn)了線(xiàn)上OOM問(wèn)題,為了不影響用戶(hù)的正常使用,最快的解決辦法就是重啟服務(wù)。
    的頭像 發(fā)表于 10-24 10:47 ?985次閱讀

    什么是OOM機(jī)制?怎么防止進(jìn)程因?yàn)?b class='flag-5'>OOM機(jī)制而被殺掉?

    有時(shí)候我們會(huì)發(fā)現(xiàn)系統(tǒng)中某個(gè)進(jìn)程會(huì)突然掛掉,通過(guò)查看系統(tǒng)日志發(fā)現(xiàn)是由于 OOM機(jī)制 導(dǎo)致進(jìn)程被殺掉。
    的頭像 發(fā)表于 02-06 11:45 ?2933次閱讀

    細(xì)說(shuō)Linux Out Of Memory機(jī)制

    有時(shí)候我們會(huì)發(fā)現(xiàn)系統(tǒng)中某個(gè)進(jìn)程會(huì)突然掛掉,通過(guò)查看系統(tǒng)日志發(fā)現(xiàn)是由于 OOM機(jī)制 導(dǎo)致進(jìn)程被殺掉。
    的頭像 發(fā)表于 02-12 09:57 ?984次閱讀

    一圖解析K8S OOM和CPU節(jié)流

    使用 Kubernetes 時(shí),內(nèi)存不足 (OOM) 錯(cuò)誤和 CPU 節(jié)流是云應(yīng)用程序中資源處理的主要難題。
    的頭像 發(fā)表于 02-15 17:17 ?1401次閱讀

    什么是OOM機(jī)制?怎么防止進(jìn)程因?yàn)?b class='flag-5'>OOM機(jī)制而被殺掉?

    有時(shí)候我們會(huì)發(fā)現(xiàn)系統(tǒng)中某個(gè)進(jìn)程會(huì)突然掛掉,通過(guò)查看系統(tǒng)日志發(fā)現(xiàn)是由于 OOM機(jī)制 導(dǎo)致進(jìn)程被殺掉。
    的頭像 發(fā)表于 06-21 08:59 ?8327次閱讀
    什么是<b class='flag-5'>OOM</b><b class='flag-5'>機(jī)制</b>?怎么防止進(jìn)程因?yàn)?b class='flag-5'>OOM</b><b class='flag-5'>機(jī)制</b>而被殺掉?

    jvm哪些區(qū)域會(huì)發(fā)生oom

    of Memory,OOM),本文將詳細(xì)介紹 JVM 內(nèi)容可能發(fā)生 OOM 的區(qū)域。OOM 是指應(yīng)用程序在申請(qǐng)分配內(nèi)存時(shí),沒(méi)有足夠的內(nèi)存供其使用,導(dǎo)致程序無(wú)法正常執(zhí)行。 堆(Heap)區(qū)域: 堆是 JVM 中最大的一塊內(nèi)存區(qū)域
    的頭像 發(fā)表于 12-05 11:51 ?1444次閱讀

    Java oom異常的原因分析

    Java中的OOM(Out of Memory)異常是指當(dāng)程序在運(yùn)行過(guò)程中無(wú)法分配足夠的內(nèi)存空間時(shí)拋出的異常。在Java中,內(nèi)存分為堆內(nèi)存(Heap)和棧內(nèi)存(Stack)。堆內(nèi)存用于存儲(chǔ)對(duì)象和數(shù)
    的頭像 發(fā)表于 12-05 13:43 ?835次閱讀

    oom異常的原因和解決方法

    一、OOM異常的原因 OOM異常的出現(xiàn)通常是由于以下幾個(gè)原因造成的: 1.1 內(nèi)存泄漏 內(nèi)存泄漏是指資源在使用完畢后沒(méi)有被正確釋放或回收,從而導(dǎo)致內(nèi)存不斷占用的現(xiàn)象。常見(jiàn)的內(nèi)存泄漏問(wèn)題包括對(duì)象未被
    的頭像 發(fā)表于 12-05 13:45 ?6705次閱讀

    Java怎么排查oom異常

    Java中的OOM(Out of Memory)異常是指當(dāng)Java虛擬機(jī)的堆內(nèi)存不足以容納新的對(duì)象時(shí)拋出的異常。OOM異常是一種常見(jiàn)的運(yùn)行時(shí)異常,經(jīng)常出現(xiàn)在長(zhǎng)時(shí)間運(yùn)行的Java應(yīng)用程序或處理大數(shù)
    的頭像 發(fā)表于 12-05 13:47 ?1288次閱讀
    百家乐官网有几种玩法| 大发888出纳柜台| 电脑版百家乐官网下注技巧| 大发888娱乐城取款| 广发百家乐官网的玩法技巧和规则| 开花财国际| 百家乐赌场在线娱乐| 百家乐官网游戏机论坛| ,瑞丰国际娱乐场| 澳门百家乐玩法| 百家乐官网开户投注| 大发888设置| 网上百家乐哪家最好| 保险百家乐官网怎么玩| 大发888赌场官方下载| 三元玄空24山坐向| 百家乐官网官方网址| 大发888游戏平台 官方| 百家乐摇色子网站| 赌场百家乐官网规则| 桐庐棋牌世界| 网络百家乐大转轮| 网上玩百家乐官网的玩法技巧和规则 | 威尼斯人娱乐城首选802com| 真人百家乐口诀| 太阳城百家乐官网红利| 大发888 迅雷下载| 网络百家乐内幕| 百家乐官网永利赌场娱乐网规则| 叶城县| 大发888娱乐城下载地址| 太阳城百家乐口诀| 玩百家乐官网必赢的心法| 哪个百家乐官网最好| 亲朋棋牌大厅下载| 香港百家乐玩| 百家乐路子分析| 百家乐官网美食坊| 网球比赛比分直播| 威尼斯人娱乐城代理注册| 百家乐游戏教程|