malloc 两种实现方式:brk 和 mmap
答案
從操作系統角度來看,進程分配內存有兩種方式,分別由兩個系統調用完成:brk 和 mmap(不考慮共享內存)。
(Data segment 和 Memory Mapping Segment 的相關內容查看這里。)
這兩種方式分配的都是虛擬內存,沒有分配物理內存。在第一次訪問已分配的虛擬地址空間的時候,發生缺頁中斷,操作系統負責分配物理內存,然后建立虛擬內存和物理內存之間的映射關系。
在標準 C 庫中,提供了 malloc / free 函數分配釋放內存,這兩個函數底層是由 brk,mmap,munmap 這些系統調用實現的。
栗子
1、進程調用 A = malloc ( 30k ) 以后,內存空間如下圖所示。malloc 函數會調用 brk 系統調用,將 _edata 指針往高地址推 30K,就完成虛擬內存分配。
你可能會問:只要把_edata + 30K 就完成內存分配了?
事實是這樣的,_edata + 30K 只是完成虛擬地址的分配,A 這塊內存現在還是沒有物理頁與之對應的,等到進程第一次讀寫 A 這塊內存的時候,發生缺頁中斷,這個時候,內核才分配 A 這塊內存對應的物理頁。也就是說,如果用 malloc 分配了 A 這塊內容,然后從來不訪問它,那么,A 對應的物理頁是不會被分配的。?
?
2、進程調用 B = malloc(40K) 以后,內存空間如下圖所示。
3、當?malloc 分配大于 128k 的內存時,使用 mmap 分配內存。在堆和棧之間找一塊空閑內存分配(對應獨立內存,而且初始化為 0 )。
這么做的原因是 brk 分配的內存需要等到高地址內存釋放以后才能釋放(例如,在 B 釋放之前,A 是不可能釋放的,這就是內存碎片產生的原因,什么時候收縮看下面),而 mmap 分配的內存可以單獨釋放。,如下圖所示,這里分配 200k 。
4、進程調用 D = malloc(100k) 以后,內存空間如下圖所示。
5、進程調用 free(C) 以后,C 對應的虛擬內存和物理內存一起釋放。
6、進程調用 free(B) 以后,如下圖所示,B 對應的虛擬內存和物理內存都沒有釋放,因為只有一個 _edata 指針,如果往回推,那么 D 這塊內存怎么辦呢?當然,B 這塊內存是可以重用的,如果這個時候再來一個 40K 的請求,那么 malloc 很可能就將?B 這塊內存返回的。?
7、進程調用 free(D) 以后,如下圖所示,B 和 D 連接起來變成一塊 140K 的空閑內存。當最高地址空間的空閑內存超過128K(可由 M_TRIM_THRESHOLD 選項調節)時,執行內存緊縮操作(trim)。在上一個步驟 free 的時候,發現最高地址空閑內存超過 128 K,于是內存緊縮,如下圖所示。
?
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的malloc 两种实现方式:brk 和 mmap的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OS / Linux / 进程的虚拟地址
- 下一篇: OS / Linux / pthread