今日問題:系統明明有很多內存,卻無法分配一片大塊內存?
這是為什麼呢?
這個問題涉及記憶體管理的一個內容-記憶體碎片
記憶體碎片在Linux很早的時候就已經出現了,了解早期記憶體碎片產生的歷史,有利於我們對它的理解。
假設現在有一塊32MB大小的內存,一開始作業系統使用了最小的一塊-4MB大小,剩餘的記憶體要留給4個行程使用,如圖(a)所示。
進程A使用了作業系統往上的10MB內存,進程B使用了進程A往上的6MB內存,進程C使用了進程B往上的8MB內存,如圖(b)所示,:
#進程D需要5MB內存,所以剩餘的內存不足以裝載進程D,這個內存末位就形成了第一個空洞(記憶體碎片)。假設某個時刻,作業系統需要運行進程D,因為系統中沒有足夠的內存,所以需要選擇一個進程來換出,為進程D騰出足夠的空間。假設作業系統選擇進程B來換出,這樣進程D就裝載到了原來進程B的位址空間裡,於是產生了第二個空洞,如圖(c)所示:
假設作業系統某個時刻需要執行進程B,也需要選擇一個進程來換出,假設進程A被換出,那麼作業系統中又產生了第三個空洞,如圖(d)所示:
隨著時間的推移,記憶體空洞會越來越多,記憶體的利用率也隨之下降,這些記憶體空洞就是我們常說的記憶體碎片。
看到這,你已經知道了什麼是記憶體碎片,同時也了解了一種記憶體管理機制-動態分割法。上述舉例其實就是動態分割法,作業系統早期使用動態分割法來管理記憶體。
怎麼解決記憶體碎片化問題?
想法其實很簡單:把多個小塊記憶體拼成一個大塊記憶體。
早期使用動態分割法的作業系統,為了解決碎片化問題,就是動態地移動進程,使得進程佔用的空間是連續的,並且所有的空閒空間也是連續,這樣就把多個小內存塊拼起來了。但是缺點也非常明顯,進程的遷移需要花費大量的時間。
#記憶體碎片分兩種:內碎片和外部碎片
內碎片:分配給程式的記憶體但未被利用的部分
外碎片:系統無法利用的小記憶體區塊(如上述動態分區法產生的碎片)
如今作業系統使用分頁或分段機制來管理內存,但仍不可避免地會產生一些記憶體碎片。
為了解決內碎片和外碎片問題,Linux引進了兩個東西:夥伴系統和slab。
夥伴系統用來解決外碎片問題,slab用來解決內碎片問題。
夥伴系統和slab也是記憶體管理中比較核心的內容,有興趣的可以去研究一下。
所以,當系統有很多內存,但無法分配一片大塊記憶體時,就是因為產生了很多內存碎片,導致系統中有很多不連續的小塊內存,表面上看系統空閒內存很多,但實際上都是一些零散的內存。
以上是系統明明有很多內存,卻無法分配一片大塊內存?的詳細內容。更多資訊請關注PHP中文網其他相關文章!