日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux内存管理_浅谈Linux内存管理

發(fā)布時間:2024/7/23 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux内存管理_浅谈Linux内存管理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1. 掃盲篇

1.1 操作系統(tǒng)存儲層次

常見的計算機存儲層次如下:

  • 寄存器:CPU提供的,讀寫ns級別,容量字節(jié)級別。
  • CPU緩存:CPU和CPU間的緩存,讀寫10ns級別,容量較大一些,百到千節(jié)。
  • 主存:動態(tài)內(nèi)存,讀寫100ns級別,容量GB級別。
  • 外部存儲介質(zhì):磁盤、SSD,讀寫ms級別,容量可擴展到TB級別。

CPU內(nèi)的緩存示意圖如下:

其中 L1d 和 L1i 都是CPU內(nèi)部的cache,

  • L1d 是數(shù)據(jù)cache。
  • L1i 是指令緩存。
  • L2是CPU內(nèi)部的,不區(qū)分指令和數(shù)據(jù)的。
  • 由于現(xiàn)代PC有多個CPU,L3緩存多個核心共用一個。

對于編程人員來說,絕大部分觀察主存和外部存儲介質(zhì)就可以了。如果要做極致的性能優(yōu)化,可以關(guān)注L1、L2、L3的cache,比如nginx的綁核操作、pthread調(diào)度會影響CPU cache等。

1.2 內(nèi)存管理概述

MMU(內(nèi)存管理單元):通過CPU將線性地址轉(zhuǎn)換成物理地址。

1.2.1 虛擬內(nèi)存

物理內(nèi)存是有限的(即使支持了熱插拔)、非連續(xù)的,不同的CPU架構(gòu)對物理內(nèi)存的組織都不同。這使得直接使用物理內(nèi)存非常復雜,為了降低使用內(nèi)存的復雜度,引入了虛擬內(nèi)存機制。

虛擬內(nèi)存抽象了應用程序物理內(nèi)存的細節(jié),只允許物理內(nèi)存保存所需的信息(按需分頁),并提供了一種保護和控制進程間數(shù)據(jù)共享數(shù)據(jù)的機制。有了虛擬內(nèi)存機制之后,每次訪問可以使用更易理解的虛擬地址,讓CPU轉(zhuǎn)換成實際的物理地址訪問內(nèi)存,降低了直接使用、管理物理內(nèi)存的門檻。

物理內(nèi)存按大小被分成頁框、頁,每塊物理內(nèi)存可以被映射為一個或多個虛擬內(nèi)存頁。這塊映射關(guān)系,由操作系統(tǒng)的頁表來保存,頁表是有層級的。層級最低的頁表,保存實際頁面的物理地址,較高層級的頁表包含指向低層級頁表的物理地址,指向頂級的頁表的地址,駐留在寄存器中。當執(zhí)行地址轉(zhuǎn)換時,先從寄存器獲取頂級頁表地址,然后依次索引,找到具體頁面的物理地址。

1.2.2 大頁機制

虛擬地址轉(zhuǎn)換的過程中,需要好幾個內(nèi)存訪問,由于內(nèi)存訪問相對CPU較慢,為了提高性能,CPU維護了一個TLB地址轉(zhuǎn)換的cache,TLB是比較重要且珍稀的緩存,對于大內(nèi)存工作集的應用程序,會因TLB命中率低大大影響到性能。

為了減少TLB的壓力,增加TLB緩存的命中率,有些系統(tǒng)會把頁的大小設為MB或者GB,這樣頁的數(shù)目少了,需要轉(zhuǎn)換的頁表項也小了,足以把虛擬地址和物理地址的映射關(guān)系,全部保存于TLB中。

1.2.3 區(qū)域概念

通常硬件會對訪問不同的物理內(nèi)存的范圍做出限制,在某些情況下設備無法對所有的內(nèi)存區(qū)域做DMA。在其他情況下,物理內(nèi)存的大小也會超過了虛擬內(nèi)存的最大可尋址大小,需要執(zhí)行特殊操作,才能訪問這些區(qū)域。這些情況下,Linux對內(nèi)存頁的可能使用情況將其分組到各自的區(qū)域中(方便管理和限制)。比如ZONE_DMA用于指明哪些可以用于DMA的區(qū)域,ZONE_HIGHMEM包含未永久映射到內(nèi)核地址空間的內(nèi)存,ZONE_NORMAL標識正常的內(nèi)存區(qū)域。

1.2.4 節(jié)點

多核CPU的系統(tǒng)中,通常是NUMA系統(tǒng)(非統(tǒng)一內(nèi)存訪問系統(tǒng))。在這種系統(tǒng)中,內(nèi)存被安排成具有不同訪問延遲的存儲組,這取決于與處理器的距離。每一個庫,被稱為一個節(jié)點,每個節(jié)點Linux構(gòu)建了一個獨立的內(nèi)存管理子系統(tǒng)。一個節(jié)點有自己的區(qū)域集、可用頁和已用頁表和各種統(tǒng)計計數(shù)器。

1.2.5 page cache

從外部存儲介質(zhì)中加載數(shù)據(jù)到內(nèi)存中,這個過程是比較耗時的,因為外部存儲介質(zhì)讀寫性能毫秒級。為了減少外部存儲設備的讀寫,Linux內(nèi)核提供了Page cache。最常見的操作,每次讀取文件時,數(shù)據(jù)都會被放入頁面緩存中,以避免后續(xù)讀取時所進行昂貴的磁盤訪問。同樣,當寫入文件時,數(shù)據(jù)被重新放置在緩存中,被標記為臟頁,定期的更新到存儲設備上,以提高讀寫性能。

1.2.6 匿名內(nèi)存

匿名內(nèi)存或者匿名映射表示不受文件系統(tǒng)支持的內(nèi)存,比如程序的堆棧隱式創(chuàng)立的,或者顯示通過mmap創(chuàng)立的。

1.2.7 內(nèi)存回收

貫穿系統(tǒng)的生命周期,一個物理頁可存儲不同類型的數(shù)據(jù),可以是內(nèi)核的數(shù)據(jù)結(jié)構(gòu),或是DMA訪問的buffer,或是從文件系統(tǒng)讀取的數(shù)據(jù),或是用戶程序分配的內(nèi)存等。

根據(jù)頁面的使用情況,Linux內(nèi)存管理對其進行了不同的處理,可以隨時釋放的頁面,稱之為可回收頁面,這類頁面為:頁面緩存或者是匿名內(nèi)存(被再次交換到硬盤上)

大多數(shù)情況下,保存內(nèi)部內(nèi)核數(shù)據(jù)并用DMA緩沖區(qū)的頁面是不能重新被回收的,但是某些情況下,可以回收使用內(nèi)核數(shù)據(jù)結(jié)構(gòu)的頁面。例如:文件系統(tǒng)元數(shù)據(jù)的內(nèi)存緩存,當系統(tǒng)處于內(nèi)存壓力情況下,可以從主存中丟棄它們。

釋放可回收的物理內(nèi)存頁的過程,被稱之為回收,可以同步或者異步的回收操作。當系統(tǒng)負載增加到一定程序時,kswapd守護進程會異步的掃描物理頁,可回收的物理頁被釋放,并逐出備份到存儲設備。

1.2.8 compaction

系統(tǒng)運行一段時間,內(nèi)存就會變得支離破碎。雖然使用虛擬村內(nèi)可以將分散的物理頁顯示為連續(xù)的物理頁,但有時需要分配較大的物理連續(xù)內(nèi)存區(qū)域。比如設備驅(qū)動程序需要一個用于DMA的大緩沖區(qū)時,或者大頁內(nèi)存機制分頁時。內(nèi)存compact可以解決了內(nèi)存碎片的問題,這個機制將被占用的頁面,從內(nèi)存區(qū)域合適的移動,以換取大塊的空閑物理頁的過程,由kcompactd守護進程完成。

1.2.9 OOM killer

機器上的內(nèi)存可能會被耗盡,并且內(nèi)核將無法回收足夠的內(nèi)存用于運行新的程序,為了保存系統(tǒng)的其余部分,內(nèi)核會調(diào)用OOM killer殺掉一些進程,以釋放內(nèi)存。

1.3 段頁機制簡介

段頁機制是操作系統(tǒng)管理內(nèi)存的一種方式,簡單的來說,就是如何管理、組織系統(tǒng)中的內(nèi)存。要理解這種機制,需要了解一下內(nèi)存尋址的發(fā)展歷程。

  • 直接尋址:早期的內(nèi)存很小,通過硬編碼的形式,直接定位到內(nèi)存地址。這種方式有著明顯的缺點:可控性弱、難以重定位、難以維護
  • 分段機制:8086處理器,尋址空間達到1MB,即地址線擴展了20位,由于制作20位的寄存器較為困難,為了能在16位的寄存器的基礎(chǔ)上,尋址20位的地址空間,引入了段的概念,即內(nèi)存地址=段基址左移4位+偏移
  • 分頁機制:隨著尋址空間的進一步擴大、虛擬內(nèi)存技術(shù)的引入,操作系統(tǒng)引入了分頁機制。引入分頁機制后,邏輯地址經(jīng)過段機制轉(zhuǎn)換得到的地址僅是中間地址,還需要通過頁機制轉(zhuǎn)換,才能得到實際的物理地址。邏輯地址 -->(分段機制) 線性地址 -->(分頁機制) 物理地址。

段頁機制詳見:https://blog.lecury.cn/2017/05/05/內(nèi)存尋址之段頁存儲機制分析/

2. 進階篇

2.1 內(nèi)存分配

2.1.1 大塊內(nèi)存的分配

掃盲篇也提到,Linux基于段頁式機制管理物理內(nèi)存,內(nèi)存被分割成一個個頁框,由多級頁表管理。除此之外,由于硬件的約束:

  • DMA處理器,只能對RAM的前16MB尋址。
  • 32位機器CPU最大尋址空間,只有4GB,對于大容量超過4GB的RAM,無法訪問所有的地址空間。

Linux還將物理內(nèi)存劃分為不同的管理區(qū):ZONE_DMA、ZONE_NORMAL、ZONE_HIGHMEM,每個管理區(qū)都有自己的描述符,也有自己的頁框分配器,示意圖如下:

對于連續(xù)頁框組的內(nèi)存分配請求,是由管理區(qū)分配器完成,每個管理區(qū)的頁框分配是通過伙伴系統(tǒng)算法來實現(xiàn)。內(nèi)核經(jīng)常請求和釋放單個頁框,為了提高性能,每個內(nèi)存管理區(qū),還定義了一個CPU頁框高速緩存,包含一些預選分配的頁框。

伙伴系統(tǒng)算法:內(nèi)核為分配一組連續(xù)的頁框而建立的一種健壯、高效的分配策略,這種策略緩解了內(nèi)存碎片的發(fā)生。算法的核心思想:是把所有的空閑頁框分組為11個塊鏈表,每個塊鏈表分別包含1、2、4、8、16、...、512、1024個連續(xù)頁框。舉個簡單的例子,說明算法的工作過程。

假設需要256個頁框的連續(xù)內(nèi)存,算法先在256個頁框的鏈表中,檢查是否還有空閑塊,如果有就分配出去。如果沒有,算法會找到下一個更大的512頁框的鏈表,如果存在空閑塊,內(nèi)核會把512頁框分割成兩部分,一半用來分配,另一半插入到256頁框的鏈表中。

2.1.2 小塊內(nèi)存的分配

伙伴系統(tǒng)算法采用頁框作為基本的內(nèi)存區(qū),這適合于大塊內(nèi)存的請求。對于小塊內(nèi)存的分配,是采用的slab分配器算法來實現(xiàn)的。slab并沒有脫離伙伴系統(tǒng)算法,而是基于伙伴系統(tǒng)分配的大內(nèi)存基礎(chǔ)上,進一步細分小內(nèi)存對象的分配。slab 緩存分配器提供了很多優(yōu)點,

  • 首先,內(nèi)核通常依賴于對小對象的分配,它們會在系統(tǒng)生命周期內(nèi)進行無數(shù)次分配,slab 緩存分配器通過對類似大小的對象進行緩存,從而避免了常見的碎片問題。
  • slab 分配器還支持通用對象的初始化,從而避免了為同一目而對一個對象重復進行初始化。
  • 最后slab 分配器還可以支持硬件緩存對齊和著色,這允許不同緩存中的對象占用相同的緩存行,從而提高緩存的利用率并獲得更好的性能。

slab分配器詳見:http://www.secretmango.com/jimb/Whitepapers/slabs/slab.html

備注: slab著色主要是為了更好的利用CPU L1 cache,所使用的地址偏移策略。如果slab分配對象后還有空間剩余,就會把剩余的空間進行著色處理,盡可能將slab對象分散在L1不同的cache line中。

2.1.3 非連續(xù)內(nèi)存的分配

把內(nèi)存區(qū)映射到一組連續(xù)的頁框是最好的選擇,這樣會充分利用高速緩存。如果對內(nèi)存區(qū)的請求不是很頻繁,那么分配非連續(xù)的頁框,會是比較好的選擇,因為這樣會避免外部碎片,缺點是內(nèi)核的頁表比較亂。Linux以下方面使用了非連續(xù)內(nèi)存區(qū):

  • 為活動交換區(qū)分配數(shù)據(jù)結(jié)構(gòu)。
  • 給某些I/O驅(qū)動程序分配緩沖區(qū)。

2.2 實存、虛存

實存:進程分配的、加載到主存中的內(nèi)存。包含來自共享庫的內(nèi)存,只要這些庫占用的頁框還在主存中,也包含所有正在使用的堆棧和堆內(nèi)存??梢酝ㄟ^ ps -o rss 查看進程的實存大小。

虛存:包含進程可以訪問的所有內(nèi)存,包含被換出、已經(jīng)分配但還未使用的內(nèi)存,以及來自共享庫的內(nèi)存??梢酝ㄟ^ ps -o vsz 查看進程的虛存大小。

舉個例子,如果進程A具有500K二進制文件并且鏈接到2500K共享庫,則具有200K的堆棧/堆分配,其中100K實際上在內(nèi)存中(其余是交換或未使用),并且它實際上只加載了1000K的共享庫然后是400K自己的二進制文件:

RSS: 400K + 1000K + 100K = 1500K VSZ: 500K + 2500K + 200K = 3200K

實存和虛存是怎么轉(zhuǎn)換的呢?當程序嘗試訪問的地址未處于實存中時,就發(fā)生頁面錯誤,操作系統(tǒng)必須以某種方式處理這種錯誤,從而使應用程序正常運行。這些操作可以是:

  • 找到頁面駐留在磁盤上的位置,并加載到主存中。
  • 重新配置MMU,更新線性地址和物理地址的映射關(guān)系。
  • 等。

隨著進程頁面錯誤的增長,主存中可用頁面越來越少,為了防止內(nèi)存完全耗盡,操作系統(tǒng)必須盡快釋放主存中暫時不用的頁面,以釋放空間供以后使用,方式如下:

  • 將修改后的頁面寫入到磁盤的專用區(qū)域上(調(diào)頁空間或者交換區(qū))。
  • 將未修改的頁面標記為空閑(沒必要寫入磁盤,因為沒有被修改)。

調(diào)頁或者交換是操作系統(tǒng)的正常部分,需要注意的是過度交換,這表示當前主存空間不足,頁面換出抖動對系統(tǒng)極為不利,會導致CPU和I/O負載升高,極端情況下,會造成操作系統(tǒng)所有的資源花費在調(diào)頁層面。

2.3 page cache

Linux中通過page cache機制來加速對磁盤文件的許多訪問,當它首次讀取或?qū)懭霐?shù)據(jù)介質(zhì)時,Linux會將數(shù)據(jù)存儲在未使用的內(nèi)存區(qū)中,通過這些區(qū)域充當緩存,如果再次讀取這些數(shù)據(jù)時,直接從內(nèi)存中快速獲取該數(shù)據(jù)。當發(fā)生寫操作時,Linux不會立刻執(zhí)行磁盤寫操作,而是把page cache中的頁面標記為臟頁,定期同步到存儲設備中。

可以通過free -m來查看page cache情況:

total used free shared buffers cached Mem: 32013 31288 724 0 241 12000 -/+ buffers/cache: 19046 12966 Swap: 32767 23134 9633

cached這列顯示了page cache的情況。

總結(jié)

以上是生活随笔為你收集整理的linux内存管理_浅谈Linux内存管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。