<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          騰訊一面:內(nèi)存滿(mǎn)了,會(huì)發(fā)生什么?

          共 7780字,需瀏覽 16分鐘

           ·

          2022-05-23 18:20

          001db19a3a4bb5a2cf6a50c3a6b977d9.webp

          作者:小林coding

          圖解網(wǎng)站:https://xiaolincoding.com/

          大家好,我是小林。

          前幾天有位讀者留言說(shuō),面騰訊時(shí),被問(wèn)了兩個(gè)內(nèi)存管理的問(wèn)題:

          d5e972c8bae5f7fd3987beb0bd8d8789.webp13146d139be0597284209bf266cde982.webp

          先來(lái)說(shuō)說(shuō)第一個(gè)問(wèn)題:虛擬內(nèi)存有什么作用?(如果你還不知道虛擬內(nèi)存概念,可以看這篇:真棒!20 張圖揭開(kāi)內(nèi)存管理的迷霧,瞬間豁然開(kāi)朗

          • 第一,由于每個(gè)進(jìn)程都有自己的頁(yè)表,所以每個(gè)進(jìn)程的虛擬內(nèi)存空間就是相互獨(dú)立的。進(jìn)程也沒(méi)有辦法訪問(wèn)其他進(jìn)程的頁(yè)表,所以這些頁(yè)表是私有的。這就解決了多進(jìn)程之間地址沖突的問(wèn)題。
          • 第二,頁(yè)表里的頁(yè)表項(xiàng)中除了物理地址之外,還有一些標(biāo)記屬性的比特,比如控制一個(gè)頁(yè)的讀寫(xiě)權(quán)限,標(biāo)記該頁(yè)是否存在等。在內(nèi)存訪問(wèn)方面,操作系統(tǒng)提供了更好的安全性。

          然后今天主要是聊聊第二個(gè)問(wèn)題,「系統(tǒng)內(nèi)存緊張時(shí),會(huì)發(fā)生什么?

          發(fā)車(chē)!

          127d775e1e8506bbfda2615c0c2b9364.webp

          內(nèi)存分配的過(guò)程是怎樣的?

          應(yīng)用程序通過(guò) malloc 函數(shù)申請(qǐng)內(nèi)存的時(shí)候,實(shí)際上申請(qǐng)的是虛擬內(nèi)存,此時(shí)并不會(huì)分配物理內(nèi)存。

          當(dāng)應(yīng)用程序讀寫(xiě)了這塊虛擬內(nèi)存,CPU 就會(huì)去訪問(wèn)這個(gè)虛擬內(nèi)存, 這時(shí)會(huì)發(fā)現(xiàn)這個(gè)虛擬內(nèi)存沒(méi)有映射到物理內(nèi)存, CPU 就會(huì)產(chǎn)生缺頁(yè)中斷,進(jìn)程會(huì)從用戶(hù)態(tài)切換到內(nèi)核態(tài),并將缺頁(yè)中斷交給內(nèi)核的 Page Fault Handler (缺頁(yè)中斷函數(shù))處理。

          缺頁(yè)中斷處理函數(shù)會(huì)看是否有空閑的物理內(nèi)存,如果有,就直接分配物理內(nèi)存,并建立虛擬內(nèi)存與物理內(nèi)存之間的映射關(guān)系。

          如果沒(méi)有空閑的物理內(nèi)存,那么內(nèi)核就會(huì)開(kāi)始進(jìn)行回收內(nèi)存的工作,回收的方式主要是兩種:直接內(nèi)存回收和后臺(tái)內(nèi)存回收。

          • 后臺(tái)內(nèi)存回收(kswapd):在物理內(nèi)存緊張的時(shí)候,會(huì)喚醒 kswapd 內(nèi)核線程來(lái)回收內(nèi)存,這個(gè)回收內(nèi)存的過(guò)程異步的,不會(huì)阻塞進(jìn)程的執(zhí)行。
          • 直接內(nèi)存回收(direct reclaim):如果后臺(tái)異步回收跟不上進(jìn)程內(nèi)存申請(qǐng)的速度,就會(huì)開(kāi)始直接回收,這個(gè)回收內(nèi)存的過(guò)程是同步的,會(huì)阻塞進(jìn)程的執(zhí)行。

          如果直接內(nèi)存回收后,空閑的物理內(nèi)存仍然無(wú)法滿(mǎn)足此次物理內(nèi)存的申請(qǐng),那么內(nèi)核就會(huì)放最后的大招了 ——觸發(fā) OOM (Out of Memory)機(jī)制

          OOM Killer 機(jī)制會(huì)根據(jù)算法選擇一個(gè)占用物理內(nèi)存較高的進(jìn)程,然后將其殺死,以便釋放內(nèi)存資源,如果物理內(nèi)存依然不足,OOM Killer 會(huì)繼續(xù)殺死占用物理內(nèi)存較高的進(jìn)程,直到釋放足夠的內(nèi)存位置。

          申請(qǐng)物理內(nèi)存的過(guò)程如下圖:

          985847d6221165a0e9bb6f5ba38ddb04.webp

          哪些內(nèi)存可以被回收?

          系統(tǒng)內(nèi)存緊張的時(shí)候,就會(huì)進(jìn)行回收內(nèi)測(cè)的工作,那具體哪些內(nèi)存是可以被回收的呢?

          主要有兩類(lèi)內(nèi)存可以被回收,而且它們的回收方式也不同。

          • 文件頁(yè)(File-backed Page):內(nèi)核緩存的磁盤(pán)數(shù)據(jù)(Buffer)和內(nèi)核緩存的文件數(shù)據(jù)(Cache)都叫作文件頁(yè)。大部分文件頁(yè),都可以直接釋放內(nèi)存,以后有需要時(shí),再?gòu)拇疟P(pán)重新讀取就可以了。而那些被應(yīng)用程序修改過(guò),并且暫時(shí)還沒(méi)寫(xiě)入磁盤(pán)的數(shù)據(jù)(也就是臟頁(yè)),就得先寫(xiě)入磁盤(pán),然后才能進(jìn)行內(nèi)存釋放。所以,回收干凈頁(yè)的方式是直接釋放內(nèi)存,回收臟頁(yè)的方式是先寫(xiě)回磁盤(pán)后再釋放內(nèi)存
          • 匿名頁(yè)(Anonymous Page):應(yīng)用程序通過(guò) mmap 動(dòng)態(tài)分配的堆內(nèi)存叫作匿名頁(yè),這部分內(nèi)存很可能還要再次被訪問(wèn),所以不能直接釋放內(nèi)存,它們回收的方式是通過(guò) Linux 的 Swap 機(jī)制,Swap 會(huì)把不常訪問(wèn)的內(nèi)存先寫(xiě)到磁盤(pán)中,然后釋放這些內(nèi)存,給其他更需要的進(jìn)程使用。再次訪問(wèn)這些內(nèi)存時(shí),重新從磁盤(pán)讀入內(nèi)存就可以了。

          文件頁(yè)和匿名頁(yè)的回收都是基于 LRU 算法,也就是優(yōu)先回收不常訪問(wèn)的內(nèi)存。LRU 回收算法,實(shí)際上維護(hù)著 active 和 inactive 兩個(gè)雙向鏈表,其中:

          • active_list 活躍內(nèi)存頁(yè)鏈表,這里存放的是最近被訪問(wèn)過(guò)(活躍)的內(nèi)存頁(yè);
          • inactive_list 不活躍內(nèi)存頁(yè)鏈表,這里存放的是很少被訪問(wèn)(非活躍)的內(nèi)存頁(yè);

          越接近鏈表尾部,就表示內(nèi)存頁(yè)越不常訪問(wèn)。這樣,在回收內(nèi)存時(shí),系統(tǒng)就可以根據(jù)活躍程度,優(yōu)先回收不活躍的內(nèi)存。

          活躍和非活躍的內(nèi)存頁(yè),按照類(lèi)型的不同,又分別分為文件頁(yè)和匿名頁(yè)。可以從 /proc/meminfo 中,查詢(xún)它們的大小,比如:

          #?grep表示只保留包含active的指標(biāo)(忽略大小寫(xiě))
          #?sort表示按照字母順序排序
          [root@xiaolin?~]#?cat?/proc/meminfo?|?grep?-i?active?|?sort
          Active:???????????901456?kB
          Active(anon):?????227252?kB
          Active(file):?????674204?kB
          Inactive:?????????226232?kB
          Inactive(anon):????41948?kB
          Inactive(file):???184284?kB

          回收內(nèi)存帶來(lái)的性能影響

          在前面我們知道了回收內(nèi)存有兩種方式。

          • 一種是后臺(tái)內(nèi)存回收,也就是喚醒 kswapd 內(nèi)核線程,這種方式是異步回收的,不會(huì)阻塞進(jìn)程。
          • 一種是直接內(nèi)存回收,這種方式是同步回收的,會(huì)阻塞進(jìn)程,這樣就會(huì)造成很長(zhǎng)時(shí)間的延遲,以及系統(tǒng)的 CPU 利用率會(huì)升高,最終引起系統(tǒng)負(fù)荷飆高。

          可被回收的內(nèi)存類(lèi)型有文件頁(yè)和匿名頁(yè):

          • 文件頁(yè)的回收:對(duì)于干凈頁(yè)是直接釋放內(nèi)存,這個(gè)操作不會(huì)影響性能,而對(duì)于臟頁(yè)會(huì)先寫(xiě)回到磁盤(pán)再釋放內(nèi)存,這個(gè)操作會(huì)發(fā)生磁盤(pán) I/O 的,這個(gè)操作是會(huì)影響系統(tǒng)性能的。
          • 匿名頁(yè)的回收:如果開(kāi)啟了 Swap 機(jī)制,那么 Swap 機(jī)制會(huì)將不常訪問(wèn)的匿名頁(yè)換出到磁盤(pán)中,下次訪問(wèn)時(shí),再?gòu)拇疟P(pán)換入到內(nèi)存中,這個(gè)操作是會(huì)影響系統(tǒng)性能的。

          可以看到,回收內(nèi)存的操作基本都會(huì)發(fā)生磁盤(pán) I/O 的,如果回收內(nèi)存的操作很頻繁,意味著磁盤(pán) I/O 次數(shù)會(huì)很多,這個(gè)過(guò)程勢(shì)必會(huì)影響系統(tǒng)的性能,整個(gè)系統(tǒng)給人的感覺(jué)就是很卡。

          下面針對(duì)回收內(nèi)存導(dǎo)致的性能影響,說(shuō)說(shuō)常見(jiàn)的解決方式。

          調(diào)整文件頁(yè)和匿名頁(yè)的回收傾向

          從文件頁(yè)和匿名頁(yè)的回收操作來(lái)看,文件頁(yè)的回收操作對(duì)系統(tǒng)的影響相比匿名頁(yè)的回收操作會(huì)少一點(diǎn),因?yàn)槲募?yè)對(duì)于干凈頁(yè)回收是不會(huì)發(fā)生磁盤(pán) I/O 的,而匿名頁(yè)的 Swap 換入換出這兩個(gè)操作都會(huì)發(fā)生磁盤(pán) I/O。

          Linux 提供了一個(gè) /proc/sys/vm/swappiness 選項(xiàng),用來(lái)調(diào)整文件頁(yè)和匿名頁(yè)的回收傾向。

          swappiness 的范圍是 0-100,數(shù)值越大,越積極使用 Swap,也就是更傾向于回收匿名頁(yè);數(shù)值越小,越消極使用 Swap,也就是更傾向于回收文件頁(yè)。

          [root@xiaolin?~]#?cat?/proc/sys/vm/swappiness
          0

          一般建議 swappiness 設(shè)置為 0(默認(rèn)就是 0),這樣在回收內(nèi)存的時(shí)候,會(huì)更傾向于文件頁(yè)的回收,但是并不代表不會(huì)回收匿名頁(yè)。

          盡早觸發(fā) kswapd 內(nèi)核線程異步回收內(nèi)存

          如何查看系統(tǒng)的直接內(nèi)存回收和后臺(tái)內(nèi)存回收的指標(biāo)?

          我們可以使用 sar -B 1 命令來(lái)觀察:

          1f3fec5aa17f4f98dc3fce928d486f31.webp

          圖中紅色框住的就是后臺(tái)內(nèi)存回收和直接內(nèi)存回收的指標(biāo),它們分別表示:

          • pgscank/s : kswapd(后臺(tái)回收線程) 每秒掃描的 page 個(gè)數(shù)。
          • pgscand/s: 應(yīng)用程序在內(nèi)存申請(qǐng)過(guò)程中每秒直接掃描的 page 個(gè)數(shù)。
          • pgsteal/s: 掃描的 page 中每秒被回收的個(gè)數(shù)(pgscank+pgscand)。

          如果系統(tǒng)時(shí)不時(shí)發(fā)生抖動(dòng),并且在抖動(dòng)的時(shí)間段里如果通過(guò) sar -B 觀察到 pgscand 數(shù)值很大,那大概率是因?yàn)椤钢苯觾?nèi)存回收」導(dǎo)致的。

          針對(duì)這個(gè)問(wèn)題,解決的辦法就是,可以通過(guò)盡早的觸發(fā)「后臺(tái)內(nèi)存回收」來(lái)避免應(yīng)用程序進(jìn)行直接內(nèi)存回收。

          什么條件下才能觸發(fā) kswapd 內(nèi)核線程回收內(nèi)存呢?

          內(nèi)核定義了三個(gè)內(nèi)存閾值(watermark,也稱(chēng)為水位),用來(lái)衡量當(dāng)前剩余內(nèi)存(pages_free)是否充裕或者緊張,分別是:

          • 頁(yè)最小閾值(pages_min);
          • 頁(yè)低閾值(pages_low);
          • 頁(yè)高閾值(pages_high);

          這三個(gè)內(nèi)存閾值會(huì)劃分為四種內(nèi)存使用情況,如下圖:

          d02a9ae42f80c62956035b26864b2a97.webp

          kswapd 會(huì)定期掃描內(nèi)存的使用情況,根據(jù)剩余內(nèi)存(pages_free)的情況來(lái)進(jìn)行內(nèi)存回收的工作。

          • 圖中綠色部分:如果剩余內(nèi)存(pages_free)大于 頁(yè)高閾值(pages_high),說(shuō)明剩余內(nèi)存是充足的;

          • 圖中藍(lán)色部分:如果剩余內(nèi)存(pages_free)在頁(yè)高閾值(pages_high)和頁(yè)低閾值(pages_low)之間,說(shuō)明內(nèi)存有一定壓力,但還可以滿(mǎn)足應(yīng)用程序申請(qǐng)內(nèi)存的請(qǐng)求;

          • 圖中橙色部分:如果剩余內(nèi)存(pages_free)在頁(yè)低閾值(pages_low)和頁(yè)最小閾值(pages_min)之間,說(shuō)明內(nèi)存壓力比較大,剩余內(nèi)存不多了。這時(shí) kswapd0 會(huì)執(zhí)行內(nèi)存回收,直到剩余內(nèi)存大于高閾值(pages_high)為止。雖然會(huì)觸發(fā)內(nèi)存回收,但是不會(huì)阻塞應(yīng)用程序,因?yàn)閮烧哧P(guān)系是異步的。

          • 圖中紅色部分:如果剩余內(nèi)存(pages_free)小于頁(yè)最小閾值(pages_min),說(shuō)明用戶(hù)可用內(nèi)存都耗盡了,此時(shí)就會(huì)觸發(fā)直接內(nèi)存回收,這時(shí)應(yīng)用程序就會(huì)被阻塞,因?yàn)閮烧哧P(guān)系是同步的。

          可以看到,當(dāng)剩余內(nèi)存頁(yè)(pages_free)小于頁(yè)低閾值(pages_low),就會(huì)觸發(fā) kswapd 進(jìn)行后臺(tái)回收,然后 kswapd 會(huì)一直回收到剩余內(nèi)存頁(yè)(pages_free)大于頁(yè)高閾值(pages_high)。

          也就是說(shuō) kswapd 的活動(dòng)空間只有 pages_low 與 pages_min 之間的這段區(qū)域,如果剩余內(nèi)測(cè)低于了 pages_min 會(huì)觸發(fā)直接內(nèi)存回收,高于了 pages_high 又不會(huì)喚醒 kswapd。

          頁(yè)低閾值(pages_low)可以通過(guò)內(nèi)核選項(xiàng) ?/proc/sys/vm/min_free_kbytes (該參數(shù)代表系統(tǒng)所保留空閑內(nèi)存的最低限)來(lái)間接設(shè)置。

          min_free_kbytes 雖然設(shè)置的是頁(yè)最小閾值(pages_min),但是頁(yè)高閾值(pages_high)和頁(yè)低閾值(pages_low)都是根據(jù)頁(yè)最小閾值(pages_min)計(jì)算生成的,它們之間的計(jì)算關(guān)系如下:

          pages_min?=?min_free_kbytes
          pages_low?=?pages_min*5/4
          pages_high?=?pages_min*3/2

          如果系統(tǒng)時(shí)不時(shí)發(fā)生抖動(dòng),并且通過(guò) sar -B 觀察到 pgscand 數(shù)值很大,那大概率是因?yàn)橹苯觾?nèi)存回收導(dǎo)致的,這時(shí)可以增大 min_free_kbytes 這個(gè)配置選項(xiàng)來(lái)及早地觸發(fā)后臺(tái)回收,然后繼續(xù)觀察 pgscand 是否會(huì)降為 0。

          增大了 min_free_kbytes 配置后,這會(huì)使得系統(tǒng)預(yù)留過(guò)多的空閑內(nèi)存,從而在一定程度上降低了應(yīng)用程序可使用的內(nèi)存量,這在一定程度上浪費(fèi)了內(nèi)存。極端情況下設(shè)置 min_free_kbytes 接近實(shí)際物理內(nèi)存大小時(shí),留給應(yīng)用程序的內(nèi)存就會(huì)太少而可能會(huì)頻繁地導(dǎo)致 OOM 的發(fā)生。

          所以在調(diào)整 min_free_kbytes 之前,需要先思考一下,應(yīng)用程序更加關(guān)注什么,如果關(guān)注延遲那就適當(dāng)?shù)卦龃?min_free_kbytes,如果關(guān)注內(nèi)存的使用量那就適當(dāng)?shù)卣{(diào)小 min_free_kbytes。

          NUMA 架構(gòu)下的內(nèi)存回收策略

          什么是 NUMA 架構(gòu)?

          再說(shuō) NUMA 架構(gòu)前,先給大家說(shuō)說(shuō) SMP 架構(gòu),這兩個(gè)架構(gòu)都是針對(duì) CPU 的。

          SMP 指的是一種多個(gè) CPU 處理器共享資源的電腦硬件架構(gòu),也就是說(shuō)每個(gè) CPU 地位平等,它們共享相同的物理資源,包括總線、內(nèi)存、IO、操作系統(tǒng)等。每個(gè) CPU 訪問(wèn)內(nèi)存所用時(shí)間都是相同的,因此,這種系統(tǒng)也被稱(chēng)為一致存儲(chǔ)訪問(wèn)結(jié)構(gòu)(UMA,Uniform Memory Access)。

          隨著 CPU 處理器核數(shù)的增多,多個(gè) CPU 都通過(guò)一個(gè)總線訪問(wèn)內(nèi)存,這樣總線的帶寬壓力會(huì)越來(lái)越大,同時(shí)每個(gè) CPU 可用帶寬會(huì)減少,這也就是 SMP 架構(gòu)的問(wèn)題。

          8a493fe553bec088d05f50407f3abf7f.webpSMP 與 NUMA 架構(gòu)

          為了解決 SMP 架構(gòu)的問(wèn)題,就研制出了 NUMA 結(jié)構(gòu),即非一致存儲(chǔ)訪問(wèn)結(jié)構(gòu)(Non-uniform memory access,NUMA)。

          NUMA 架構(gòu)將每個(gè) CPU ?進(jìn)行了分組,每一組 CPU 用 Node 來(lái)表示,一個(gè) Node 可能包含多個(gè) CPU 。

          每個(gè) Node 有自己獨(dú)立的資源,包括內(nèi)存、IO 等,每個(gè) Node 之間可以通過(guò)互聯(lián)模塊總線(QPI)進(jìn)行通信,所以,也就意味著每個(gè) Node 上的 CPU 都可以訪問(wèn)到整個(gè)系統(tǒng)中的所有內(nèi)存。但是,訪問(wèn)遠(yuǎn)端 Node 的內(nèi)存比訪問(wèn)本地內(nèi)存要耗時(shí)很多。

          NUMA 架構(gòu)跟回收內(nèi)存有什么關(guān)系?

          在 NUMA 架構(gòu)下,當(dāng)某個(gè) Node 內(nèi)存不足時(shí),系統(tǒng)可以從其他 Node 尋找空閑內(nèi)存,也可以從本地內(nèi)存中回收內(nèi)存。

          具體選哪種模式,可以通過(guò) /proc/sys/vm/zone_reclaim_mode 來(lái)控制。它支持以下幾個(gè)選項(xiàng):

          • 0 (默認(rèn)值):在回收本地內(nèi)存之前,在其他 Node 尋找空閑內(nèi)存;
          • 1:只回收本地內(nèi)存;
          • 2:只回收本地內(nèi)存,在本地回收內(nèi)存時(shí),可以將文件頁(yè)中的臟頁(yè)寫(xiě)回硬盤(pán),以回收內(nèi)存。
          • 4:只回收本地內(nèi)存,在本地回收內(nèi)存時(shí),可以用 swap 方式回收內(nèi)存。

          在使用 NUMA 架構(gòu)的服務(wù)器,如果系統(tǒng)出現(xiàn)還有一半內(nèi)存的時(shí)候,卻發(fā)現(xiàn)系統(tǒng)頻繁觸發(fā)「直接內(nèi)存回收」,導(dǎo)致了影響了系統(tǒng)性能,那么大概率是因?yàn)?zone_reclaim_mode 沒(méi)有設(shè)置為 0 ,導(dǎo)致當(dāng)本地內(nèi)存不足的時(shí)候,只選擇回收本地內(nèi)存的方式,而不去使用其他 Node 的空閑內(nèi)存。

          雖然說(shuō)訪問(wèn)遠(yuǎn)端 Node 的內(nèi)存比訪問(wèn)本地內(nèi)存要耗時(shí)很多,但是相比內(nèi)存回收的危害而言,訪問(wèn)遠(yuǎn)端 Node 的內(nèi)存帶來(lái)的性能影響還是比較小的。因此,zone_reclaim_mode 一般建議設(shè)置為 0。

          如何保護(hù)一個(gè)進(jìn)程不被 OOM 殺掉呢?

          在系統(tǒng)空閑內(nèi)存不足的情況,進(jìn)程申請(qǐng)了一個(gè)很大的內(nèi)存,如果直接內(nèi)存回收都無(wú)法回收出足夠大的空閑內(nèi)存,那么就會(huì)觸發(fā) OOM 機(jī)制,內(nèi)核就會(huì)根據(jù)算法選擇一個(gè)進(jìn)程殺掉。

          Linux 到底是根據(jù)什么標(biāo)準(zhǔn)來(lái)選擇被殺的進(jìn)程呢?這就要提到一個(gè)在 Linux 內(nèi)核里有一個(gè) oom_badness() 函數(shù),它會(huì)把系統(tǒng)中可以被殺掉的進(jìn)程掃描一遍,并對(duì)每個(gè)進(jìn)程打分,得分最高的進(jìn)程就會(huì)被首先殺掉。

          進(jìn)程得分的結(jié)果受下面這兩個(gè)方面影響:

          • 第一,進(jìn)程已經(jīng)使用的物理內(nèi)存頁(yè)面數(shù)。
          • 第二,每個(gè)進(jìn)程的 OOM 校準(zhǔn)值 oom_score_adj。它是可以通過(guò) /proc/[pid]/oom_score_adj 來(lái)配置的。我們可以在設(shè)置 -1000 到 1000 之間的任意一個(gè)數(shù)值,調(diào)整進(jìn)程被 OOM Kill 的幾率。

          函數(shù) oom_badness() 里的最終計(jì)算方法是這樣的:

          //?points?代表打分的結(jié)果
          //?process_pages?代表進(jìn)程已經(jīng)使用的物理內(nèi)存頁(yè)面數(shù)
          //?oom_score_adj?代表?OOM?校準(zhǔn)值
          //?totalpages?代表系統(tǒng)總的可用頁(yè)面數(shù)
          points?=?process_pages?+?oom_score_adj*totalpages/1000

          用「系統(tǒng)總的可用頁(yè)面數(shù)」乘以 「OOM 校準(zhǔn)值 oom_score_adj」再除以 1000,最后再加上進(jìn)程已經(jīng)使用的物理頁(yè)面數(shù),計(jì)算出來(lái)的值越大,那么這個(gè)進(jìn)程被 OOM Kill 的幾率也就越大

          每個(gè)進(jìn)程的 oom_score_adj 默認(rèn)值都為 0,所以最終得分跟進(jìn)程自身消耗的內(nèi)存有關(guān),消耗的內(nèi)存越大越容易被殺掉。我們可以通過(guò)調(diào)整 oom_score_adj 的數(shù)值,來(lái)改成進(jìn)程的得分結(jié)果:

          • 如果你不想某個(gè)進(jìn)程被首先殺掉,那你可以調(diào)整該進(jìn)程的 oom_score_adj,從而改變這個(gè)進(jìn)程的得分結(jié)果,降低該進(jìn)程被 OOM 殺死的概率。
          • 如果你想某個(gè)進(jìn)程無(wú)論如何都不能被殺掉,那你可以將 oom_score_adj 配置為 -1000。

          我們最好將一些很重要的系統(tǒng)服務(wù)的 oom_score_adj 配置為 -1000,比如 sshd,因?yàn)檫@些系統(tǒng)服務(wù)一旦被殺掉,我們就很難再登陸進(jìn)系統(tǒng)了。

          但是,不建議將我們自己的業(yè)務(wù)程序的 oom_score_adj 設(shè)置為 -1000,因?yàn)闃I(yè)務(wù)程序一旦發(fā)生了內(nèi)存泄漏,而它又不能被殺掉,這就會(huì)導(dǎo)致隨著它的內(nèi)存開(kāi)銷(xiāo)變大,OOM killer 不停地被喚醒,從而把其他進(jìn)程一個(gè)個(gè)給殺掉。

          參考資料:

          • https://time.geekbang.org/column/article/277358
          • https://time.geekbang.org/column/article/75797
          • https://www.jianshu.com/p/e40e8813842f

          總結(jié)

          內(nèi)核在給應(yīng)用程序分配物理內(nèi)存的時(shí)候,如果空閑物理內(nèi)存不夠,那么就會(huì)進(jìn)行內(nèi)存回收的工作,主要有兩種方式:

          • 后臺(tái)內(nèi)存回收:在物理內(nèi)存緊張的時(shí)候,會(huì)喚醒 kswapd 內(nèi)核線程來(lái)回收內(nèi)存,這個(gè)回收內(nèi)存的過(guò)程異步的,不會(huì)阻塞進(jìn)程的執(zhí)行。
          • 直接內(nèi)存回收:如果后臺(tái)異步回收跟不上進(jìn)程內(nèi)存申請(qǐng)的速度,就會(huì)開(kāi)始直接回收,這個(gè)回收內(nèi)存的過(guò)程是同步的,會(huì)阻塞進(jìn)程的執(zhí)行。

          可被回收的內(nèi)存類(lèi)型有文件頁(yè)和匿名頁(yè):

          • 文件頁(yè)的回收:對(duì)于干凈頁(yè)是直接釋放內(nèi)存,這個(gè)操作不會(huì)影響性能,而對(duì)于臟頁(yè)會(huì)先寫(xiě)回到磁盤(pán)再釋放內(nèi)存,這個(gè)操作會(huì)發(fā)生磁盤(pán) I/O 的,這個(gè)操作是會(huì)影響系統(tǒng)性能的。
          • 匿名頁(yè)的回收:如果開(kāi)啟了 Swap 機(jī)制,那么 Swap 機(jī)制會(huì)將不常訪問(wèn)的匿名頁(yè)換出到磁盤(pán)中,下次訪問(wèn)時(shí),再?gòu)拇疟P(pán)換入到內(nèi)存中,這個(gè)操作是會(huì)影響系統(tǒng)性能的。

          文件頁(yè)和匿名頁(yè)的回收都是基于 LRU 算法,也就是優(yōu)先回收不常訪問(wèn)的內(nèi)存。回收內(nèi)存的操作基本都會(huì)發(fā)生磁盤(pán) I/O 的,如果回收內(nèi)存的操作很頻繁,意味著磁盤(pán) I/O 次數(shù)會(huì)很多,這個(gè)過(guò)程勢(shì)必會(huì)影響系統(tǒng)的性能。

          針對(duì)回收內(nèi)存導(dǎo)致的性能影響,常見(jiàn)的解決方式。

          • 設(shè)置 /proc/sys/vm/swappiness,調(diào)整文件頁(yè)和匿名頁(yè)的回收傾向,盡量?jī)A向于回收文件頁(yè);
          • 設(shè)置 /proc/sys/vm/min_free_kbytes,調(diào)整 kswapd 內(nèi)核線程異步回收內(nèi)存的時(shí)機(jī);
          • 設(shè)置 ?/proc/sys/vm/zone_reclaim_mode,調(diào)整 NUMA 架構(gòu)下內(nèi)存回收策略,建議設(shè)置為 0,這樣在回收本地內(nèi)存之前,會(huì)在其他 Node 尋找空閑內(nèi)存,從而避免在系統(tǒng)還有很多空閑內(nèi)存的情況下,因本地 Node 的本地內(nèi)存不足,發(fā)生頻繁直接內(nèi)存回收導(dǎo)致性能下降的問(wèn)題;

          在經(jīng)歷完直接內(nèi)存回收后,空閑的物理內(nèi)存大小依然不夠,那么就會(huì)觸發(fā) OOM 機(jī)制,OOM killer 就會(huì)根據(jù)每個(gè)進(jìn)程的內(nèi)存占用情況和 oom_score_adj 的值進(jìn)行打分,得分最高的進(jìn)程就會(huì)被首先殺掉。

          我們可以通過(guò)調(diào)整進(jìn)程的 /proc/[pid]/oom_score_adj 值,來(lái)降低被 OOM killer 殺掉的概率。

          完!

          圖解系列文章:小林的網(wǎng)站上線啦!小林的圖解系統(tǒng),大曝光!
          不鴿了,小林的「圖解網(wǎng)絡(luò) 3.0 」發(fā)布!
          瀏覽 27
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  黄视频免费大全 | xxxx国产 | 日韩高清精品在线 | 夜夜嗨色刺激 | 操逼系列 |