<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>

          為什么 Linux 需要 Swapping

          共 5157字,需瀏覽 11分鐘

           ·

          2020-11-30 22:08

          為什么這么設(shè)計(jì)(Why’s THE Design)是一系列關(guān)于計(jì)算機(jī)領(lǐng)域中程序設(shè)計(jì)決策的文章,我們?cè)谶@個(gè)系列的每一篇文章中都會(huì)提出一個(gè)具體的問題并從不同的角度討論這種設(shè)計(jì)的優(yōu)缺點(diǎn)、對(duì)具體實(shí)現(xiàn)造成的影響。如果你有想要了解的問題,可以在文章下面留言。

          對(duì) Linux 稍有了解的人都知道,Linux 會(huì)將物理的隨機(jī)讀取內(nèi)存(Random Access Memory、RAM)按頁(yè)分割成 4KB 大小的內(nèi)存塊,而今天要介紹的?Swapping?機(jī)制就與內(nèi)存息息相關(guān),它是操作系統(tǒng)將物理內(nèi)存頁(yè)中的內(nèi)容拷貝到硬盤上交換空間(Swap Space)以釋放內(nèi)存的過程,物理內(nèi)存和硬盤上的交換分區(qū)組成了操作系統(tǒng)上可用的虛擬內(nèi)存,而這些交換空間都是系統(tǒng)管理員預(yù)先配置好的[^1]。

          圖 1 - Linux Swapping

          正是因?yàn)?Linux 上的所有進(jìn)程都會(huì)通過虛擬內(nèi)存這一層抽象間接與物理內(nèi)存打交道,而 Swapping 也充分利用了該特性,它能夠讓應(yīng)用程序看到操作系統(tǒng)內(nèi)存充足的假象,然而并不知道它使用的部分虛擬內(nèi)存其實(shí)在磁盤上,因?yàn)閮?nèi)存和磁盤的讀寫速度上的巨大差異,這部分虛擬內(nèi)存的讀寫非常緩慢,我們?cè)?為什么 CPU 訪問硬盤很慢 曾經(jīng)介紹過:

          在 SSD 中隨機(jī)訪問 4KB 數(shù)據(jù)所需要的時(shí)間是訪問主存的 1,500 倍,機(jī)械磁盤的尋道時(shí)間是訪問主存的 100,000 倍[^2]

          如此巨大的性能差異使得觸發(fā) Swapping 的進(jìn)程可能會(huì)遇到性能損失,同一個(gè)頁(yè)面的頻繁換入換出會(huì)導(dǎo)致極其明顯的性能抖動(dòng),如果沒有相應(yīng)的背景知識(shí),遇到類似的問題可能會(huì)很難查到根本原因,例如 MySQL 在錯(cuò)誤配置 NUMA 時(shí)就會(huì)出現(xiàn)內(nèi)存頁(yè)頻繁換入換出,影響服務(wù)質(zhì)量的問題。

          Linux 提供了兩種不同的方法啟用 Swapping,分別是 Swap 分區(qū)(Swap Partition)和 Swap 文件(Swapfile):

          • Swap 分區(qū)是硬盤上的獨(dú)立區(qū)域,該區(qū)域只會(huì)用于交換分區(qū),其他的文件不能存儲(chǔ)在該區(qū)域上,我們可以使用?swapon -s?命令查看當(dāng)前系統(tǒng)上的交換分區(qū);
          • Swap 文件是文件系統(tǒng)中的特殊文件,它與文件系統(tǒng)中的其他文件也沒有太多的區(qū)別;

          Swap 分區(qū)的大小是需要系統(tǒng)管理員手動(dòng)設(shè)定的,然而不同的場(chǎng)景最好設(shè)置不同交換分區(qū)大小,例如:桌面系統(tǒng)的交換分區(qū)大小可以是系統(tǒng)內(nèi)存的兩倍,這可以讓我們同時(shí)運(yùn)行更多的應(yīng)用程序;服務(wù)器的交換分區(qū)應(yīng)該關(guān)閉或者使用少量的交換分區(qū),不過一旦啟用交換分區(qū),就應(yīng)該引入監(jiān)控監(jiān)控應(yīng)用程序的性能。

          我們到現(xiàn)在已經(jīng)對(duì) Linux 上的 Swapping 有了一定的了解,接下來回到這篇文章想要討論的問題 — 『為什么 Linux 需要 Swapping』,我們將從以下兩個(gè)方面介紹 Swapping 解決的問題、觸發(fā)入口和執(zhí)行路徑:

          • Swapping 可以直接將進(jìn)程中使用相對(duì)較少的頁(yè)面換出內(nèi)存,立刻給正在執(zhí)行的進(jìn)程分配內(nèi)存;
          • Swapping 可以將進(jìn)程中的閑置頁(yè)面換出內(nèi)存,為其他進(jìn)程未來使用內(nèi)存做好準(zhǔn)備;

          內(nèi)存不足

          當(dāng)系統(tǒng)需要的內(nèi)存超過了可用的物理內(nèi)存時(shí),內(nèi)核會(huì)將內(nèi)存中不常使用的內(nèi)存頁(yè)交換到磁盤上為當(dāng)前進(jìn)程讓出內(nèi)存,保證正在執(zhí)行的進(jìn)程的可用性,這個(gè)內(nèi)存回收的過程是強(qiáng)制的直接內(nèi)存回收(Direct Page Reclaim)。

          圖 2 - 直接內(nèi)存回收

          直接內(nèi)存回收是在 Linux 調(diào)用?__alloc_pages_nodemask?申請(qǐng)新內(nèi)存頁(yè)時(shí)觸發(fā)的,該函數(shù)會(huì)先在空閑頁(yè)列表中查找是否有可用的頁(yè)面,如果不存在可用頁(yè)面,就會(huì)進(jìn)入?__alloc_pages_slowpath?函數(shù)分配內(nèi)存頁(yè),與從空閑列表中直接查找內(nèi)存也相比,該函數(shù)會(huì)通過以下步驟分配內(nèi)存:

          static?inline?struct?page?*?__alloc_pages_slowpath(gfp_t?gfp_mask,?unsigned?int?order,?struct?alloc_context?*ac)?{
          ????...
          ????if?(alloc_flags?&?ALLOC_KSWAPD)
          ????????wake_all_kswapds(order,?gfp_mask,?ac);

          ????page?=?get_page_from_freelist(gfp_mask,?order,?alloc_flags,?ac);
          ????if?(page)?goto?got_pg;

          ????if?(can_direct_reclaim?&&?(costly_order?||?(order?>?0?&&?ac->migratetype?!=?MIGRATE_MOVABLE))?&&?!gfp_pfmemalloc_allowed(gfp_mask))?{
          ????????page?=?__alloc_pages_direct_compact(gfp_mask,?order,?alloc_flags,?ac,?INIT_COMPACT_PRIORITY,?&compact_result);
          ????????if?(page)?goto?got_pg;
          ????????...
          ????}

          ?retry:
          ????page?=?__alloc_pages_direct_reclaim(gfp_mask,?order,?alloc_flags,?ac,?&did_some_progress);
          ????page?=?__alloc_pages_direct_compact(gfp_mask,?order,?alloc_flags,?ac,?compact_priority,?&compact_result);
          ????page?=?__alloc_pages_may_oom(gfp_mask,?order,?ac,?&did_some_progress);
          ?got_pg:
          ????return?page;
          }
          1. 喚醒?kswapd?線程在后臺(tái)回收內(nèi)存并嘗試調(diào)用?get_page_from_freelist?從空閑列表中快速獲取內(nèi)存頁(yè);
          2. 昂貴的內(nèi)存申請(qǐng)會(huì)先調(diào)用?__alloc_pages_direct_compact?嘗試壓縮內(nèi)存頁(yè),并在壓縮后的內(nèi)存中調(diào)用?get_page_from_freelist?查找空閑的內(nèi)存頁(yè);
          3. 調(diào)用?__alloc_pages_direct_reclaim?直接回收并分配新的內(nèi)存頁(yè);
          4. 再次調(diào)用?__alloc_pages_direct_compact?嘗試壓縮內(nèi)存并獲取空閑內(nèi)存頁(yè);
          5. 調(diào)用?__alloc_pages_may_oom?分配內(nèi)存,如果內(nèi)存分配失敗會(huì)觸發(fā)內(nèi)存不足警告隨機(jī)殺死操作系統(tǒng)上的幾個(gè)進(jìn)程;

          雖然獲取內(nèi)存頁(yè)的步驟已經(jīng)經(jīng)過了大量的刪減,但是其中展示了 Linux 在內(nèi)存也不足時(shí)獲取內(nèi)存的幾個(gè)常見方法:內(nèi)存壓縮、直接回收以及觸發(fā)內(nèi)存不足錯(cuò)誤殺掉部分進(jìn)程。

          內(nèi)存閑置

          應(yīng)用程序在啟動(dòng)階段使用的大量?jī)?nèi)存在啟動(dòng)后往往都不會(huì)使用,通過后臺(tái)運(yùn)行的守護(hù)進(jìn)程,我們可以將這部分只使用一次的內(nèi)存交換到磁盤上為其他內(nèi)存的申請(qǐng)預(yù)留空間。kswapd 是 Linux 負(fù)責(zé)頁(yè)面置換(Page replacement)的守護(hù)進(jìn)程,它也是負(fù)責(zé)交換閑置內(nèi)存的主要進(jìn)程,它會(huì)在空閑內(nèi)存低于一定水位時(shí),回收內(nèi)存頁(yè)中的空閑內(nèi)存保證系統(tǒng)中的其他進(jìn)程可以盡快獲得申請(qǐng)的內(nèi)存,如下圖所示:

          圖 3 - Linux 空閑頁(yè)面水位

          當(dāng)空閑頁(yè)面小于?WMARK_LOW?時(shí),kswapd 進(jìn)程才會(huì)開始工作,它會(huì)將內(nèi)存頁(yè)交換到磁盤上直到空閑頁(yè)面的水位回到?WMARK_HIGH,不過當(dāng)空閑頁(yè)面的水位低于?WMARK_MIN?時(shí)會(huì)觸發(fā)上一節(jié)提到的內(nèi)存直接回收,而水位高于?WMARK_HIGH?則意味著空閑內(nèi)存充足,不需要進(jìn)行回收。

          Linux 操作系統(tǒng)采用最近最少使用(Least Recently Used、LRU)算法置換內(nèi)存中的頁(yè)面,系統(tǒng)中的每個(gè)區(qū)都會(huì)在內(nèi)存中持有?active_list?和?inactive_list?兩種鏈表,其中前者包含活躍的內(nèi)存頁(yè),后者中存儲(chǔ)的內(nèi)存頁(yè)都是回收的候選頁(yè)面,除此之外,Linux 還會(huì)在將?lru_list?根據(jù)內(nèi)存頁(yè)的特性分成如下幾種:

          enum?lru_list?{
          ?LRU_INACTIVE_ANON?=?LRU_BASE,
          ?LRU_ACTIVE_ANON?=?LRU_BASE?+?LRU_ACTIVE,
          ?LRU_INACTIVE_FILE?=?LRU_BASE?+?LRU_FILE,
          ?LRU_ACTIVE_FILE?=?LRU_BASE?+?LRU_FILE?+?LRU_ACTIVE,
          ?LRU_UNEVICTABLE,
          ?NR_LRU_LISTS
          };

          其中包含?ANON?的表示匿名內(nèi)存頁(yè),這些內(nèi)存頁(yè)存儲(chǔ)了與文件無關(guān)的進(jìn)程堆棧等內(nèi)容,而包含?FILE?的表示與文件相關(guān)的內(nèi)存,也就是程序文件或者數(shù)據(jù)對(duì)應(yīng)的內(nèi)存,而最后的?LRU_UNEVICTABLE?表示禁止回收的內(nèi)存頁(yè)。

          圖 4 - 活躍鏈表和不活躍鏈表

          每當(dāng)內(nèi)存頁(yè)被訪問時(shí),Linux 都會(huì)將被訪問的內(nèi)存頁(yè)移到鏈表的頭部,所以在活躍鏈表末尾的是鏈表中『最老的』內(nèi)存頁(yè),守護(hù)進(jìn)程 kswapd 的作用是平衡兩個(gè)鏈表的長(zhǎng)度,將活躍鏈表末尾的內(nèi)存頁(yè)移至不活躍鏈表的隊(duì)首等待回收,而函數(shù)?shrink_zones?會(huì)負(fù)責(zé)回收 LRU 鏈表中的不活躍內(nèi)存頁(yè)。

          總結(jié)

          很多人認(rèn)為當(dāng)系統(tǒng)內(nèi)存不足時(shí)應(yīng)該立即觸發(fā)內(nèi)存不足(Out of memory、OOM)并殺掉進(jìn)程,但是 Swapping 其實(shí)為系統(tǒng)管理員提供了另外一種選擇,利用磁盤的交換空間避免程序被直接退出,以降低服務(wù)質(zhì)量的代價(jià)換取服務(wù)的部分可用性。Linux 中的 Swapping 機(jī)制主要是為內(nèi)存不足和內(nèi)存閑置兩種常見的情況存在的

          • Swapping 可以直接將進(jìn)程中使用相對(duì)較少的頁(yè)面換出內(nèi)存:當(dāng)系統(tǒng)需要的內(nèi)存超過了可用的物理內(nèi)存時(shí),內(nèi)核會(huì)將內(nèi)存中不常使用的內(nèi)存頁(yè)交換到磁盤上為當(dāng)前進(jìn)程讓出內(nèi)存,保證正在執(zhí)行的進(jìn)程的可用性;
          • Swapping 可以將進(jìn)程中的閑置頁(yè)面換出內(nèi)存:應(yīng)用程序在啟動(dòng)階段使用的大量?jī)?nèi)存在啟動(dòng)后往往都不會(huì)使用,通過后臺(tái)運(yùn)行的守護(hù)進(jìn)程,我們可以將這部分只使用一次的內(nèi)存交換到磁盤上為其他內(nèi)存申請(qǐng)預(yù)留空間;

          關(guān)于是否應(yīng)該開啟 Swapping 的討論其實(shí)非常多,我們?cè)诮裉煲膊粦?yīng)該一刀切地認(rèn)為必須開啟或者禁用 Swapping,我們?nèi)匀恍枰治鰣?chǎng)景并利用好 Linux 為我們提供的這一機(jī)制,例如 Kubernetes 要求禁用 Swapping,我們就應(yīng)該遵循社區(qū)提出的建議,在部署 Kubernetes 的機(jī)器上關(guān)閉這一特性[^3]。到最后,我們還是來看一些比較開放的相關(guān)問題,有興趣的讀者可以仔細(xì)思考一下下面的問題:

          • Linux 提供了哪些參數(shù)來控制 Swapping 的行為?
          • 通過降低服務(wù)質(zhì)量的代價(jià)換取部分可用在哪些場(chǎng)景下是可取的?

          參考資料

          • Kubelet/Kubernetes should work with Swap Enabled #53533 https://github.com/kubernetes/kubernetes/issues/53533
          • Linux Performance: Why You Should Almost Always Add Swap Space https://haydenjames.io/linux-performance-almost-always-add-swap-space/
          • Do we really need swap on modern systems? https://www.redhat.com/en/blog/do-we-really-need-swap-modern-systems


          良許個(gè)人微信


          添加良許個(gè)人微信即送3套程序員必讀資料


          → 精選技術(shù)資料共享

          → 高手如云交流社群





          本公眾號(hào)全部博文已整理成一個(gè)目錄,請(qǐng)?jiān)诠娞?hào)里回復(fù)「m」獲?。?/span>

          推薦閱讀:

          TCP/IP 基礎(chǔ)知識(shí)總結(jié)

          到底什么是Docker?什么是K8S?

          微信第 1 行代碼曝光!


          5T技術(shù)資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機(jī),樹莓派,等等。在公眾號(hào)內(nèi)回復(fù)「1024」,即可免費(fèi)獲?。?!


          瀏覽 57
          點(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>
                  日韩精品免费无码视频 | 青娱乐性爱视频 | 五月天亚洲丁香无码 | 精品久久久久久久久久久 | 天天综合~91入口 |