記憶體分配的原理

2021-08-19 23:41:51 字數 2386 閱讀 7394

記憶體分配的原理

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

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

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

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

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

缺頁中斷

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

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

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

2、查詢/分配乙個物理頁

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

4、建立對映關係(虛擬位址到實體地址)

分配記憶體的過程

一、malloc小於128k的記憶體

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

2、程序呼叫a=malloc(30k)以後,記憶體空間如圖2

malloc函式會呼叫brk系統呼叫,將_edata指標往高位址推30k,就完成虛擬記憶體分配。

二、malloc小於128k的記憶體

使用mmap分配記憶體,在堆和棧之間找一塊空閒記憶體分配

1、程序呼叫c=malloc(200k)以後,記憶體空間如圖4

預設情況下,malloc函式分配記憶體,如果請求記憶體大於128k,那就不是去推_edata指標了,而是利用mmap系統呼叫,從堆和棧的中間分配一塊虛擬記憶體。

2、程序呼叫d=malloc(100k)以後,記憶體空間如圖5

記憶體釋放

1、釋放c記憶體:程序呼叫free(c)以後,c對應的虛擬記憶體和物理記憶體一起釋放

2、釋放b記憶體:程序呼叫free(b)以後,如圖7所示

我們發現釋放掉c與b是不同的,mmap方式的記憶體釋放沒有什麼特別的,但brk的不同

這裡我們要考慮乙個問題,brk方式的記憶體如何釋放

b對應的虛擬記憶體和物理記憶體都沒有釋放,因為只有乙個_edata指標,如果往回推,那麼d這塊記憶體怎麼辦呢?

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

當程序呼叫free(d)以後,如圖8所示:

b和d連線起來,變成一塊140k的空閒記憶體。

預設情況下:

當最高位址空間的空閒記憶體超過128k時,執行記憶體緊縮操作(trim)。在上乙個步驟free的時候,發現最高位址空閒記憶體超過128k,於是記憶體緊縮,變成圖9所示。

brk和mmap的對比
相關問題:既然堆記憶體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 program命令檢視。majflt代表major fault,中文名叫大錯誤,minflt代表minor fault,中文名叫小錯誤。這兩個數值表示乙個程序自啟動以來所發生的缺頁中斷的次數。發成缺頁中斷後,執行了那些操作?...

棧記憶體的分配原理

什麼是堆記憶體分配棧記憶體分配 在c 中,記憶體分成5個區,他們分別是堆 棧 自由儲存區 全域性 靜態儲存區和常量儲存區。棧,就是那些由編譯器在需要的時候分配,在不需要的時候自動清楚的變數的儲存區。裡面的變數通常是區域性變數 函式引數等。堆,就是那些由new分配的記憶體塊,他們的釋放編譯器不去管,由...

malloc記憶體分配原理

一 malloc的工作機制 它有乙個將可用的記憶體塊連線為乙個長長的列表的所謂空閒鍊錶。呼叫malloc函式時,它沿連線表尋找乙個大到足以滿足使用者請求所需要的記憶體塊。然後,將該記憶體塊一分為二 一塊的大小與使用者請求的大小相等,另一塊的大小就是剩下的位元組 接下來,將分配給使用者的那塊記憶體傳給...