最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

圖解Linux內(nèi)存回收之LRU算法(超級(jí)詳細(xì)~)

2022-05-19 20:27 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿
  • 內(nèi)存 是操作系統(tǒng)非常重要的資源,操作系統(tǒng)要運(yùn)行一個(gè)程序,必須先把程序代碼段的指令和數(shù)據(jù)段的變量從硬盤加載到內(nèi)存中,然后才能被運(yùn)行。如下圖所示:



  • 但內(nèi)存資源是有限的,隨著系統(tǒng)中運(yùn)行的進(jìn)程越來(lái)越多,系統(tǒng)中可用的內(nèi)存就會(huì)越來(lái)越少。那么,當(dāng)可用內(nèi)存不足時(shí),Linux 內(nèi)核是怎么處理的呢?

  • 本文將會(huì)介紹,當(dāng)可用內(nèi)存不足時(shí),Linux 內(nèi)核的處理方式。

一、內(nèi)存不足的處理方式

  • 我們思考一下,當(dāng)系統(tǒng)的可用內(nèi)存不足時(shí),進(jìn)程繼續(xù)申請(qǐng)內(nèi)存會(huì)發(fā)生什么事情?

  • 當(dāng)系統(tǒng)的可用內(nèi)存不足時(shí),內(nèi)核為了保證進(jìn)程有足夠的內(nèi)存可用,將會(huì)對(duì)內(nèi)存進(jìn)行回收工作。內(nèi)存回收工作主要包括以下幾個(gè)步驟:

  1. 內(nèi)核為了加速某些操作(如文件 I/O),會(huì)對(duì)操作的結(jié)果進(jìn)行緩存(如文件頁(yè)緩存),而緩存使用的內(nèi)存是可以被回收的。所以,當(dāng)可用內(nèi)存不足時(shí),首先會(huì)回收內(nèi)核中的緩存。

  2. 如果回收內(nèi)核緩存后,系統(tǒng)的可用內(nèi)存仍然處于不足。那么,內(nèi)核將會(huì)觸發(fā) swap 機(jī)制。swap 機(jī)制會(huì)將某些進(jìn)程所占用的內(nèi)存交換(寫入)到硬盤中,然后釋放這些內(nèi)存,從而讓系統(tǒng)有更多可用的內(nèi)存。本文將會(huì)重點(diǎn)介紹 swap 機(jī)制。

  3. 如果觸發(fā) swap 機(jī)制后,系統(tǒng)的可用內(nèi)存仍不能滿足系統(tǒng)需求,那么將會(huì)觸發(fā) OOM(Out Of Memory) 機(jī)制。OOM 機(jī)制將會(huì)挑選一些進(jìn)程,然后將這些進(jìn)程殺死來(lái),從而獲取更多可用內(nèi)存。


  • 由于回收內(nèi)存的方式有三種,所以本文重點(diǎn)以 swap 機(jī)制作為分析對(duì)象,來(lái)介紹當(dāng)內(nèi)存不足時(shí),內(nèi)核是怎么進(jìn)行內(nèi)存回收工作的。

【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺(jué)得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。∏?00名進(jìn)群領(lǐng)取,額外贈(zèng)送一份價(jià)值699的內(nèi)核資料包(含視頻教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ? ?


二、swap機(jī)制原理

  • 在分析 swap 機(jī)制的實(shí)現(xiàn)前,我們先來(lái)介紹一下 swap 機(jī)制的原理。

本文使用 Linux-2.6.23 版本內(nèi)核。

  • swap 這個(gè)單詞是 交換 的意思,顧名思義就是把某些進(jìn)程所占用的內(nèi)存交換(寫入)到硬盤,然后把內(nèi)存釋放給操作系統(tǒng),這樣操作系統(tǒng)就有更多可用的內(nèi)存。如下圖所示:



  • 由于 swap 機(jī)制的本質(zhì)是將進(jìn)程所占用的內(nèi)存寫入到硬盤中,然后釋放這些內(nèi)存。那么,就涉及到應(yīng)該將哪些進(jìn)程的內(nèi)存交換到硬盤中。

  • 每個(gè)進(jìn)程都不希望自己占用的內(nèi)存被交換到硬盤中,因?yàn)閮?nèi)存被交換到硬盤后,如果進(jìn)程要使用到這些內(nèi)存時(shí),必須先將這些內(nèi)存從硬盤中加載到內(nèi)存中,才能繼續(xù)使用,這樣進(jìn)程的性能將會(huì)大打折扣。正因?yàn)檫@個(gè)原因,內(nèi)核必須提供一種最優(yōu)的方案來(lái)挑選一些內(nèi)存交換到硬盤,并且對(duì)進(jìn)程性能的影響降到最小。

由于進(jìn)程的內(nèi)存空間分為多個(gè)段,如 代碼段、數(shù)據(jù)段、mmap段、堆段 和 棧段 等。那么,哪些段的內(nèi)存會(huì)被交換到硬盤中呢? 答案就是:所有段的內(nèi)存都有可能交換到硬盤。不過(guò)對(duì)于 代碼段 和 mmap段 這些與文件有映射關(guān)系的內(nèi)存區(qū),只需要將數(shù)據(jù)寫回到文件即可(由于代碼段的內(nèi)容不會(huì)改變,所以不用進(jìn)行回寫)。

  • 而對(duì)于 數(shù)據(jù)段、堆段 和 棧段 這些段中的內(nèi)存頁(yè),由于沒(méi)有與文件進(jìn)行映射(稱為 匿名內(nèi)存頁(yè)),所以內(nèi)核必須提供一個(gè)文件(或硬盤分區(qū))來(lái)存儲(chǔ)這些內(nèi)存頁(yè)的數(shù)據(jù),這個(gè)文件(或硬盤分區(qū))被稱為 交換分區(qū)。

  • 從上面的分析可以得出兩個(gè)重要的信息:

  1. 匿名內(nèi)存頁(yè):沒(méi)有與任何文件進(jìn)行映射的內(nèi)存頁(yè)。

  2. 交換分區(qū):用于存儲(chǔ)匿名內(nèi)存頁(yè)數(shù)據(jù)的文件或硬盤分區(qū)。

  • 下面主要介紹當(dāng)系統(tǒng)內(nèi)存不足時(shí),內(nèi)核是怎樣將進(jìn)程的 匿名內(nèi)存頁(yè) 寫入到 交換分區(qū) 中,并且回收這些 匿名內(nèi)存頁(yè) 的。

1. LRU 內(nèi)存淘汰算法

  • 當(dāng)系統(tǒng)內(nèi)存不足,并且觸發(fā) swap機(jī)制 時(shí),內(nèi)核應(yīng)該選擇哪些 匿名內(nèi)存頁(yè) 寫入到 交換分區(qū) 中呢?如果隨機(jī)選擇一些 匿名內(nèi)存頁(yè) 寫入到 交換分區(qū),就有可能出現(xiàn)如下問(wèn)題:

把某個(gè)進(jìn)程的 匿名內(nèi)存頁(yè) 寫入到 交換分區(qū) 后,進(jìn)程又馬上訪問(wèn)這個(gè)內(nèi)存頁(yè),從而又要把這個(gè)內(nèi)存頁(yè)從 交換分區(qū) 中讀入到內(nèi)存中。這樣只會(huì)增加系統(tǒng)的負(fù)荷,并且不能解決系統(tǒng)內(nèi)存不足的問(wèn)題。

  • 為了解決這個(gè)問(wèn)題,Linux 內(nèi)核引入了 LRU內(nèi)存淘汰算法,用過(guò) Memcached 或者 Redis 的同學(xué)應(yīng)該都了解過(guò) LRU算法。當(dāng)系統(tǒng)內(nèi)存不足時(shí),Memcached 和 Redis 都是使用 LRU算法 來(lái)淘汰內(nèi)存的。

LRU(Least Recently Used) 中文翻譯是 最近最少使用 的意思,其原理就是:當(dāng)內(nèi)存不足時(shí),淘汰系統(tǒng)中最少使用的內(nèi)存,這樣對(duì)系統(tǒng)性能的損耗是最小的。

  • 為了實(shí)現(xiàn) LRU算法,內(nèi)核維護(hù)了兩個(gè)雙向鏈表:active_list 和 inactive_list。下面介紹下這兩個(gè)鏈表的作用:

  1. active_list:活躍內(nèi)存頁(yè)鏈表。也就是說(shuō)進(jìn)程會(huì)經(jīng)常訪問(wèn)這個(gè)鏈表中的內(nèi)存頁(yè),所以進(jìn)行內(nèi)存淘汰時(shí),不應(yīng)該淘汰這個(gè)鏈表中的內(nèi)存頁(yè)。

  2. inactive_list:不活躍內(nèi)存頁(yè)鏈表。也就是說(shuō)進(jìn)程很少會(huì)訪問(wèn)這個(gè)鏈表中的內(nèi)存頁(yè),所以進(jìn)行內(nèi)存淘汰時(shí),主要淘汰這個(gè)鏈表中的內(nèi)存頁(yè)。

  • 在 Linux 內(nèi)核中,每個(gè) 內(nèi)存區(qū)(zone) 都會(huì)維護(hù)著一個(gè) active_list 和一個(gè) inactive_list。內(nèi)存區(qū) 是內(nèi)存管理中的一個(gè)對(duì)象,為了描述更加清晰,我們暫時(shí)當(dāng)成內(nèi)核中只有一個(gè)內(nèi)存區(qū),也就是說(shuō)暫時(shí)認(rèn)為內(nèi)核中只維護(hù)著一個(gè) active_list 和一個(gè) inactive_list。如下圖所示:



  • 另外,每個(gè)內(nèi)存頁(yè)都有個(gè) PG_referenced 的標(biāo)志位,表示此內(nèi)存頁(yè)是否被訪問(wèn)過(guò),這個(gè)標(biāo)志位在內(nèi)存回收過(guò)程中起著至關(guān)重要的作用。

  • 當(dāng)某個(gè)進(jìn)程申請(qǐng)一個(gè)匿名內(nèi)存頁(yè)時(shí),內(nèi)核會(huì)把這個(gè)內(nèi)存頁(yè)添加到 活躍內(nèi)存頁(yè)鏈表(active_list) 中,并且將 PG_referenced 標(biāo)志位設(shè)置為 0。如下圖所示:



  • 而當(dāng)某個(gè)匿名內(nèi)存頁(yè)被進(jìn)程訪問(wèn)時(shí),根據(jù)內(nèi)存頁(yè)所在的 LRU 鏈表作不同的操作:

  1. 如果內(nèi)存頁(yè)原來(lái)處于 活躍鏈表 中,那么就會(huì)把此內(nèi)存頁(yè)的 PG_referenced 設(shè)置為 1。

  2. 如果內(nèi)存頁(yè)原來(lái)處于 非活躍鏈表 中,并且 PG_referenced 為 0。那么將內(nèi)存頁(yè)的 PG_referenced 標(biāo)志位設(shè)置為 1。

  3. 如果內(nèi)存頁(yè)原來(lái)處于 非活躍鏈表 中,并且 PG_referenced 為 1。那么將會(huì)把內(nèi)存頁(yè)從 非活躍鏈表 移動(dòng)到 活躍鏈表,并且將 PG_referenced 設(shè)置為 0。

  • 下圖展示了上述各種情況的流轉(zhuǎn)過(guò)程:



  • 而當(dāng)系統(tǒng)內(nèi)存不足時(shí),需要進(jìn)行內(nèi)存淘汰過(guò)程。內(nèi)存頁(yè)淘汰過(guò)程與上述過(guò)程剛好相反,下面介紹一下內(nèi)存頁(yè)淘汰的過(guò)程。

  • 內(nèi)存淘汰時(shí),只能從 非活躍鏈表 中進(jìn)行淘汰,淘汰過(guò)程如下:

  1. 從 非活躍鏈表 的尾部開(kāi)始進(jìn)行內(nèi)存淘汰,如果內(nèi)存頁(yè)的 PG_referenced 標(biāo)志位為 1 時(shí),將跳過(guò)此內(nèi)存頁(yè),并且將此內(nèi)存頁(yè)的 PG_referenced 標(biāo)志位設(shè)置為 0。

  2. 如果內(nèi)存頁(yè)的 PG_referenced 標(biāo)志位為 0 時(shí),那么將此內(nèi)存頁(yè)寫入到 交換分區(qū) 中,并且將所有與此內(nèi)存頁(yè)的映射解除綁定,然后釋放此內(nèi)存頁(yè)。

  • 上述過(guò)程是由 shrink_inactive_list 函數(shù)完成,如下圖所示:



  • 另外,處于 活躍鏈表 的內(nèi)存頁(yè)也有衰退的過(guò)程,衰退過(guò)程如下:

  1. 如果內(nèi)存頁(yè)的 PG_referenced 標(biāo)志位為 1,那么衰退過(guò)程將會(huì)把此內(nèi)存頁(yè)的 PG_referenced 標(biāo)志位設(shè)置為 0。

  2. 如果內(nèi)存頁(yè)的 PG_referenced 標(biāo)志位為 0,那么衰退過(guò)程將會(huì)把此內(nèi)存頁(yè)移動(dòng)到 非活躍鏈表 中。

  • 上述過(guò)程是由 shrink_active_list 函數(shù)完成,如下圖所示:




2. LRU算法狀態(tài)流轉(zhuǎn)

  • 我們最后以一張狀態(tài)流轉(zhuǎn)圖來(lái)描述 LRU 算法的過(guò)程:



三、總結(jié)

  • 本文主要介紹了 Linux 內(nèi)核內(nèi)存回收過(guò)程中使用的 LRU 算法的原理.


圖解Linux內(nèi)存回收之LRU算法(超級(jí)詳細(xì)~)的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
平度市| 烟台市| 观塘区| 彭阳县| SHOW| 内乡县| 尉犁县| 吕梁市| 耒阳市| 龙江县| 博兴县| 武威市| 格尔木市| 龙海市| 顺平县| 苏尼特右旗| 桦南县| 正定县| 玛沁县| 宁晋县| 宁远县| 古田县| 六盘水市| 庄浪县| 台东县| 河津市| 庆城县| 志丹县| 玉龙| 康平县| 英山县| 济宁市| 东海县| 延安市| 旅游| 扎鲁特旗| 噶尔县| 杭锦后旗| 缙云县| 盖州市| 大同县|