對Linux記憶體管理的思考

2021-08-25 20:31:48 字數 2586 閱讀 1144

**:

經典!看了對低端物理記憶體和高3

核心的虛擬記憶體被連續對映到最低端的物理記憶體。這是所有問題的開始。

為什麼要把核心的虛擬位址空間連續地對映到物理記憶體最低端?這個根本不是個問題。開發人員或是出於效率的原因或是出於實現的原因,就是做了這樣的設計。但這種設計卻引發了很多令人困惑的問題。

假設我們使用32位版本核心,系統裝有2g物理記憶體,下面所說的「核心的虛擬記憶體」是指核心前896m虛擬記憶體。

"核心將自己的虛擬記憶體連續對映到低端物理記憶體"到底會產生什麼樣的結果?是說低端那896m物理記憶體已被核心所佔而不能另做它用?昨天討論記憶體的帖子裡給出了否定答案,看起來這是個很老的問題了。

書上往往會還有這樣的話語:核心只能使用最低端896m物理;超過896m的記憶體稱之為「高階記憶體」,無法被核心直接使用。初學者讀到這裡,總覺得**不對勁,卻又道不出個所以然來。

既然核心已將自己的虛擬記憶體映**,核心頁表裡entries是怎樣的呢?在entry中,我們當前感興趣的有兩項:對映位址與present標誌位。對映位址嘛,肯定安排好了。present標誌位是不是1呢?不妨認為是1。這樣一來,從核心的頁表上來看,前896m的物理記憶體的的確確被核心所「占用」,只要核心引用相應的虛擬位址,核心就會訪問到相應的實體地址,不會發生任何意外。但是,如前面所說,程序也是可以使用這塊記憶體的。如果某個程序的某個虛擬位址對映到了前896m中的某一段,那麼核心與程序都可通過各自的頁表訪問到這塊記憶體。這樣會不會發生衝突呢?

描述頁幀的資料結構是page結構體,乙個頁幀是否空閒正是取決於對應page結構體中的引用數。那麼核心對映的那896m物理記憶體是否空閒呢?除了核心**及靜態資料所佔的物理頁外,其它的全是空閒狀態。也就是說《記憶體管理子系統》可以把這些記憶體分配出去。昨天帖子裡說的「被核心映**不等於被核心使用了」就是這麼回事。核心頁表裡的內容是說,前896m物理記憶體處於一種ready to use的狀態,然而沒有被核心使用的記憶體,程序也可以使用。在896m記憶體中,核心不能使用「被程序使用的記憶體」,即核心不能引用相應的頁表裡的內容,即核心不可使用相應的虛擬位址。

核心是怎麼使用自己的虛擬位址的呢?她怎麼知道哪一段的虛擬位址已經《被自己使用了》或者《因為程序而不能使用》?即核心如何管理自己的虛擬位址。

先看核心如何管理程序的虛擬位址。當程序需要記憶體時,核心首先會為程序分配一段虛擬位址,即所謂的memory region。由於程序虛擬位址的使用情況記錄在vm_area_struct中,所有的vm_area_struct都按照順序連線在乙個鍊錶上,因此尋找某大小的虛擬位址十分簡單,掃瞄這個鍊錶,碰到一塊大於或等於[所申請記憶體大小]的連續位址,便用新的vm_area_struct記錄下來,並插到鍊錶的合適位置,這塊虛擬位址便被標記為「已用」了。其實這就是作業系統理論裡所講的first fit。早期的unix就是這樣管理物理記憶體的,而這裡用之管理程序的虛擬記憶體。核心為程序分配記憶體的步驟如下:

一、找到合適大小的虛擬位址段;

二、向申請物理頁幀;

三、在程序頁表中建立兩者的對映關係。

然而核心為《自己》分配記憶體時,只有#第二步#。

沒有第三步,是因為一開始的時候,核心頁表已經做好了對映。那第一步呢?核心為什麼沒有像程序一樣《尋找合適大小的虛擬位址段》這一步驟?

核心自己需要記憶體時,總是向slab層申請(?)。需要建立新的資料結構,需要乙個buffer時,slab便為之分配一塊連續的記憶體。核心不需要對這塊記憶體做對映,只要這塊連續的物理內存在前896m之內,它本來就處於一種「預備被核心使用」的狀態。從slab裡分出來後,它就「正式被核心使用」。那麼說到底,核心怎麼管理虛擬位址呢?核心沒有「額外管理」,具體使用哪一塊虛擬記憶體取決於slab分配哪塊物理記憶體。slab分配哪塊物理記憶體又取決了。=

結論是:buddy system管理了核心的虛擬記憶體。嚴格來說,buddy system在管理前896m物理記憶體時隨便把核心的虛擬記憶體也管理了。對程序來說,分配虛擬記憶體與分配物理記憶體是分開的步驟;對於核心來說,分配了物理記憶體就等於分配了虛擬記憶體。核心為自己分配的記憶體究竟在虛擬記憶體的什麼位置取決於分[配到的記憶體的頁幀]在物理記憶體中的哪個位置。程序需要額外的結構體記錄虛擬記憶體的使用的情況;核心虛擬記憶體的使用情況就是前896m物理記憶體的使用情況。換句話說,一旦程序申請到了前896m物理記憶體中的某一塊,就相當於侵占了核心的虛擬位址空間,就相當於核心對應的虛擬位址段已經被使用。由於所有對物理記憶體的申請都由buddy system應答,核心為自己申請記憶體時,不可能再獲得被[程序占用的物理記憶體]所對應的[虛擬位址],也就不可能去[引用相應的頁表],衝突也就避免了。當然,如果核心有bug,指標使用不慎,很容易破壞程序的記憶體。

這樣一來,問題都解決了。前896m物理記憶體由核心與程序混用。但核心只能使用這896m物理記憶體(因為它的頁表對映是固定的),而程序可以使用任何地方的物理記憶體(因為它的頁表可以隨意設定)。核心高128m留作其它用途,可以隨意對映。核心不能直接使用的記憶體即「高階記憶體」。當核心的線性位址空間大於物理記憶體時,「高階」便不存在了。這種情況實際上有兩種可能:一是核心線性位址空間太大,如使用64位系統;二是系統物理記憶體太小,如機器僅配有512m記憶體。兩者都是的結果。

管理程序虛擬記憶體時,利用分頁,可以把虛擬位址隨意對映到任何實體地址,這才是我們印象中「分頁機制的常規用法」。相反的,核心管理自己的虛擬記憶體時,利用分頁,把「一塊虛擬記憶體固定到一塊物理記憶體」,反倒限制核心能使用的內存在物理記憶體中的位置,與我們印象中分頁機制的常規作用相悖。初學者總有種「說不清道不明的不協調感」,大概就是這個原因吧。

記憶體管理的思考方式

首先看到 引用計數 這個詞,我們會不自覺想到 某處有某物多少 而將注意力放到計數上。但是更加正確的思考方式是 objective c記憶體管理中的alloc retain release dealloc方法分別是nsbject類的alloc類方法 retain例項方法 release例項方法 dea...

自動記憶體管理技術的思考

我是乙個學過一點c 語言的人。在c 中,沒有自動記憶體管理,卻有很多可以值得借鑑的思路。我認為乙個記憶體,申請了,卻不用,然後,不用了,卻不釋放,都是一種資源浪費,而不是說,程式最終都會在某乙個時刻 釋放就叫防止記憶體洩漏了。就算有一小部分記憶體我是永遠都用不上,洩露了,而相對有大部分記憶體不能好好...

linux的記憶體管理

linux的記憶體管理 linux的記憶體分為 物理記憶體和虛擬記憶體。物理記憶體就是系統硬體提供的記憶體大小,是真正的記憶體。虛擬記憶體 虛擬記憶體就是為了滿足物理記憶體的不足而提出的策略,它是利用磁碟空間虛擬出的一塊邏輯記憶體,用作虛擬記憶體的磁碟空間被稱為交換空間 swap space 使用場...