linux記憶體配置之mmap,munmp,brk執行個體講解,mmapbrk

來源:互聯網
上載者:User

linux記憶體配置之mmap,munmp,brk執行個體講解,mmapbrk

Linux 的虛擬記憶體管理有幾個關鍵概念:

1、每個進程都有獨立的虛擬位址空間,進程訪問的虛擬位址並不是真正的物理地址;

2、虛擬位址可通過每個進程上的頁表(在每個進程的核心虛擬位址空間)與物理地址進行映射,獲得真正物理地址;

3、如果虛擬位址對應物理地址不在實體記憶體中,則產生缺頁中斷,真正分配物理地址,同時更新進程的頁表;如果此時實體記憶體已耗盡,則根據記憶體替換演算法淘汰部分頁面至物理磁碟中。

基於以上認識,進行了如下分析:

一、Linux 虛擬位址空間如何分布?

Linux 使用虛擬位址空間,大大增加了進程的定址空間,由低地址到高地址分別為:

1、唯讀段:該部分空間只能讀,不可寫;(包括:程式碼片段、rodata 段(C常量字串和#define定義的常量))

2、資料區段:儲存全域變數、靜態變數的空間;

3、堆 :就是平時所說的動態記憶體, malloc/new 大部分都來源於此。其中堆頂的位置可通過函數 brk 和 sbrk 進行動態調整。

4、檔案對應地區 :如動態庫、共用記憶體等映射物理空間的記憶體,一般是mmap 函數所分配的虛擬位址空間。

5、棧:用於維護函數調用的上下文空間,一般為 8M ,可通過 ulimit –s 查看。

6、核心虛擬空間:使用者代碼不可見的記憶體地區,由核心管理(頁表就存放在核心虛擬空間)。

是 32 位系統典型的虛擬位址空間分布(來自《深入理解電腦系統》)。

32 位系統有4G 的地址空間::

其中 0x08048000~0xbfffffff 是使用者空間,0xc0000000~0xffffffff 是核心空間,包括核心代碼和資料、與進程相關的資料結構(如頁表、核心棧)等。另外,%esp 執行棧頂,往低地址方向變化;brk/sbrk 函數控制堆頂_edata往高地址方向變化。

64位系統結果怎樣呢? 64 位元系統是否擁有 2^64 的地址空間嗎?

事實上, 64 位元系統的虛擬位址空間劃分發生了改變:

1、地址空間大小不是2^32,也不是2^64,而一般是2^48。因為並不需要 2^64 這麼大的定址空間,過大空間只會導致資源的浪費。64位Linux一般使用48位來表示虛擬位址空間,40位表示物理地址,

這可通過 /proc/cpuinfo 來查看

address sizes : 40 bits physical, 48 bits virtual

2、其中,0x0000000000000000~0x00007fffffffffff 表示使用者空間, 0xFFFF800000000000~ 0xFFFFFFFFFFFFFFFF 表示核心空間,共提供 256TB(2^48) 的定址空間。

這兩個區間的特點是,第 47 位與 48~63 位相同,若這些位為 0 表示使用者空間,否則表示核心空間。

3、使用者空間由低地址到高地址仍然是唯讀段、資料區段、堆、檔案對應地區和棧;

二、malloc和free是如何分配和釋放記憶體?

如何查看進程發生缺頁中斷的次數?

用ps -o majflt,minflt -C program命令查看。

majflt代表major fault,中文名叫大錯誤,minflt代表minor fault,中文名叫小錯誤。

這兩個數值表示一個進程自啟動以來所發生的缺頁中斷的次數。

發成缺頁中斷後,執行了那些操作?

當一個進程發生缺頁中斷的時候,進程會陷入核心態,執行以下操作:

1、檢查要訪問的虛擬位址是否合法

2、尋找/分配一個物理頁

3、填充物理頁內容(讀取磁碟,或者直接置0,或者啥也不幹)

4、建立映射關係(虛擬位址到物理地址)

重新執行發生缺頁中斷的那條指令

如果第3步,需要讀取磁碟,那麼這次缺頁中斷就是majflt,否則就是minflt。

記憶體配置的原理

從作業系統角度來看,進程分配記憶體有兩種方式,分別由兩個系統調用完成:brk和mmap(不考慮共用記憶體)。

1、brk是將資料區段(.data)的最高地址指標_edata往高地址推;

2、mmap是在進程的虛擬位址空間中(堆和棧中間,稱為檔案對應地區的地方)找一塊閒置虛擬記憶體。

這兩種方式分配的都是虛擬記憶體,沒有分配實體記憶體。在第一次訪問已指派的虛擬位址空間的時候,發生缺頁中斷,作業系統負責分配實體記憶體,然後建立虛擬記憶體和實體記憶體之間的映射關係。

在標準C庫中,提供了malloc/free函數分配釋放記憶體,這兩個函數底層是由brk,mmap,munmap這些系統調用實現的。

下面以一個例子來說明記憶體配置的原理:

情況一、malloc小於128k的記憶體,使用brk分配記憶體,將_edata往高地址推(只分配虛擬空間,不對應實體記憶體(因此沒有初始化),第一次讀/寫資料時,引起核心缺頁中斷,核心才分配對應的實體記憶體,然後虛擬位址空間建立映射關係),如:

1、進程啟動的時候,其(虛擬)記憶體空間的初始布局1所示。

其中,mmap記憶體對應檔是在堆和棧的中間(例如libc-2.2.93.so,其它資料檔案等),為了簡單起見,省略了記憶體對應檔。

_edata指標(glibc裡面定義)指向資料區段的最高地址。

2、進程調用A=malloc(30K)以後,記憶體空間2:

malloc函數會調用brk系統調用,將_edata指標往高地址推30K,就完成虛擬記憶體分配。

你可能會問:只要把_edata+30K就完成記憶體配置了?

事實是這樣的,_edata+30K只是完成虛擬位址的分配,A這塊記憶體現在還是沒有物理頁與之對應的,等到進程第一次讀寫A這塊記憶體的時候,發生缺頁中斷,這個時候,核心才分配A這塊記憶體對應的物理頁。也就是說,如果用malloc分配了A這塊內容,然後從來不訪問它,那麼,A對應的物理頁是不會被分配的。

3、進程調用B=malloc(40K)以後,記憶體空間3。

情況二、malloc大於128k的記憶體,使用mmap分配記憶體,在堆和棧之間找一塊空閑記憶體配置(對應獨立記憶體,而且初始化為0),如:

4、進程調用C=malloc(200K)以後,記憶體空間4:

預設情況下,malloc函數分配記憶體,如果請求記憶體大於128K(可由M_MMAP_THRESHOLD選項調節),那就不是去推_edata指標了,而是利用mmap系統調用,從堆和棧的中間分配一塊虛擬記憶體。

這樣子做主要是因為::

brk分配的記憶體需要等到高地址記憶體釋放以後才能釋放(例如,在B釋放之前,A是不可能釋放的,這就是記憶體片段產生的原因,什麼時候緊縮看下面),而mmap分配的記憶體可以單獨釋放。

當然,還有其它的好處,也有壞處,再具體下去,有興趣的同學可以去看glibc裡面malloc的代碼了。

5、進程調用D=malloc(100K)以後,記憶體空間5;

6、進程調用free(C)以後,C對應的虛擬記憶體和實體記憶體一起釋放。

7、進程調用free(B)以後,7所示:

B對應的虛擬記憶體和實體記憶體都沒有釋放,因為只有一個_edata指標,如果往回推,那麼D這塊記憶體怎麼辦呢?

當然,B這塊記憶體,是可以重用的,如果這個時候再來一個40K的請求,那麼malloc很可能就把B這塊記憶體返回回去了。

8、進程調用free(D)以後,8所示:

B和D串連起來,變成一塊140K的空閑記憶體。

9、預設情況下:

當最高地址空間的空閑記憶體超過128K(可由M_TRIM_THRESHOLD選項調節)時,執行記憶體緊縮操作(trim)。在上一個步驟free的時候,發現最高地址空閑記憶體超過128K,於是記憶體緊縮,變成圖9所示。

三、既然堆內記憶體brk和sbrk不能直接釋放,為什麼不全部使用 mmap 來分配,munmap直接釋放呢?

既然堆內片段不能直接釋放,導致疑似“記憶體泄露”問題,為什麼 malloc 不全部使用 mmap 來實現呢(mmap分配的記憶體可以會通過 munmap 進行 free ,實現真正釋放)?而是僅僅對於大於 128k 的大塊記憶體才使用 mmap ?

其實,進程向 OS 申請和釋放地址空間的介面 sbrk/mmap/munmap 都是系統調用,頻繁調用系統調用都比較消耗系統資源的。並且, mmap 申請的記憶體被 munmap 後,重新申請會產生更多的缺頁中斷。例如使用 mmap 分配 1M 空間,第一次調用產生了大量缺頁中斷 (1M/4K 次 ) ,當munmap 後再次分配 1M 空間,會再次產生大量缺頁中斷。缺頁中斷是核心行為,會導致核心態CPU消耗較大。另外,如果使用 mmap 分配小記憶體,會導致地址空間的分區更多,核心的管理負擔更大。

同時堆是一個連續空間,並且堆內片段由於沒有歸還 OS ,如果可重用片段,再次訪問該記憶體很可能不需產生任何系統調用和缺頁中斷,這將大大降低 CPU 的消耗。 因此, glibc 的 malloc 實現中,充分考慮了 sbrk 和 mmap 行為上的差異及優缺點,預設分配大塊記憶體 (128k) 才使用 mmap 獲得地址空間,也可通過 mallopt(M_MMAP_THRESHOLD, ) 來修改這個臨界值。

四、如何查看進程的缺頁中斷資訊?

可通過以下命令查看缺頁中斷資訊

ps -o majflt,minflt -C

ps -o majflt,minflt -p

其中::majflt 代表 major fault ,指大錯誤;

minflt 代表 minor fault ,指小錯誤。

這兩個數值表示一個進程自啟動以來所發生的缺頁中斷的次數。

其中 majflt 與 minflt 的不同是::

majflt 表示需要讀寫磁碟,可能是記憶體對應頁面在磁碟中需要load 到實體記憶體中,也可能是此時實體記憶體不足,需要淘汰部分物理頁面至磁碟中。

五、C語言的記憶體配置方式與malloc

C語言跟記憶體配置方式

(1) 從靜態儲存地區分配。記憶體在程式編譯的時候就已經分配好,這塊記憶體在程式的整個運行期間都存在。例如全域變數,static變數。

(2) 在棧上建立。在執行函數時,函數內局部變數的儲存單元都可以在棧上建立,函數執行結束時這些儲存單元自動被釋放。棧記憶體配置運

算內建於處理器的指令集中,效率很高,但是分配的記憶體容量有限。

(3)從堆上分配,亦稱動態記憶體分配。程式在啟動並執行時候用malloc或new申請任意多少的記憶體,程式員自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多

C語言跟記憶體申請相關的函數主要有 alloc,calloc,malloc,free,realloc,sbrk等.其中alloc是向棧申請記憶體,因此無需釋放. malloc分配的記憶體是位於堆中的,並且沒有初始化記憶體的內容,因此基本上malloc之後,調用函數memset來初始化這部分的記憶體空間.calloc則將初始化這部分的記憶體,設定為0. 而realloc則對malloc申請的記憶體進行大小的調整.申請的記憶體最終需要通過函數free來釋放. 而sbrk則是增加資料區段的大小;

malloc/calloc/free基本上都是C函數庫實現的,跟OS無關.C函數庫內部通過一定的結構來儲存當前有多少可用記憶體.如果程式 malloc的大小超出了庫裡所留存的空間,那麼將首先調用brk系統調用來增加可用空間,然後再分配空間.free時,釋放的記憶體並不立即返回給os, 而是保留在內部結構中. 可以打個比方: brk類似於批發,一次性的向OS申請大的記憶體,而malloc等函數則類似於零售,滿足程式運行時的要求.這套機制類似於緩衝.

使用這套機制的原因: 系統調用不能支援任意大小的記憶體配置(有的系統調用只支援固定大小以及其倍數的記憶體申請,這樣的話,對於小記憶體的分配會造成浪費; 系統調用申請記憶體代價昂貴,涉及到使用者態和核心態的轉換.

函數malloc()和calloc()都可以用來分配動態記憶體空間,但兩者稍有區別。

在Linux系統上,程式被載入記憶體時,核心為使用者進程地址空間建立了程式碼片段、資料區段和堆棧段,在資料區段與堆棧段之間的空閑地區用於動態記憶體分配。

核心資料結構mm_struct中的成員變數start_code和end_code是進程程式碼片段的起始和終止地址,start_data和 end_data是進程資料區段的起始和終止地址,start_stack是進程堆棧段起始地址,start_brk是進程動態記憶體分配起始地址(堆的起始 地址),還有一個 brk(堆的當前最後地址),就是動態記憶體分配當前的終止地址。

C語言的動態記憶體分配基本函數是malloc(),在Linux上的基本實現是通過核心的brk系統調用。brk()是一個非常簡單的系統調用,只是簡單地改變mm_struct結構的成員變數brk的值。

mmap系統調用實現了更有用的動態記憶體分配功能,可以將一個磁碟檔案的全部或部分內容映射到使用者空間中,進程讀寫檔案的操作變成了讀寫記憶體的操作。在 linux/mm/mmap.c檔案的do_mmap_pgoff()函數,是mmap系統調用實現的核心。do_mmap_pgoff()的代碼,只是建立了一個vm_area_struct結構,並把file結構的參數賦值給其成員變數m_file,並沒有把檔案內容實際裝入記憶體。

Linux記憶體管理的基本思想之一,是只有在真正訪問一個地址的時候才建立這個地址的物理映射。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.