上文vm_area_struct中還有乙個vm_mm沒講到,而這個vm_mm,則是聯絡vm_area_struct和它所屬程序的關鍵紐帶。它指向的是負責管理記憶體的mm_struct結構體,而這個mm_struct又可以從task_struct這個幾乎記錄了乙個程序所有資訊的結構體中獲取。
其中mmap指向vma鍊錶的頭節點,mm_rb指向vma紅黑樹的根節點。map_count是vma的總個數,total_vm是程序位址空間的總大小(以page為單位)。
mmap_cache儲存了上一次找到的vma,根據區域性性原理,下一次要用到的vma正好是上次使用的vma的可能性是比較大的,因此使用find_vma()函式查詢vma時,會首先從mmap_cache中找,找到了就直接返回。
vma = mm->mmap_cache;
if (vma && vma->vm_end > addr && vma->vm_start <= addr)
return vma;
沒找到再去紅黑樹裡面找:
rb_node = mm->mm_rb.rb_node;
vma = null;
while (rb_node) else
rb_node = rb_node->rb_right;
}if (vma)
mm->mmap_cache = vma;
return vma;
這種mmap_cache的命中率通常只有35%-50%,之後核心開發者又在此基礎上,設計了新的vma cache方案。
當然,你出於某種目的,也可以指定就街道上的某間房子(呼叫mmap()時指定引數addr),如果這間房子正好是空的,就可以分配給你。
if (addr)
這裡的房子有點特殊,街道上房間的總數是固定的,每個房間的大小是4平方公尺(頁面大小4kb),只要是相鄰的空房間,就可以組成乙個空房子。房間總數也是有限的(3gb記憶體的話差不多是75萬個房間),你來晚了,或者你獅子大開口,要乙個50萬房間的空房子(比如通過malloc(2g)),那就有可能出現分配不到的情況(可用虛擬位址空間不足)。
如果新建的vma和它位址上緊挨著的vma有相同的屬性,且基於相同的對映物件(比如是同乙個檔案),則還會產生vma的合併(上下兩層樓打通,做成乙個躍層)。減少vma的數量有利於減輕核心的管理工作量,降低系統開銷。如果沒有發生合併,則需要呼叫insert_vm_struct( )在vma鍊錶和vma紅黑樹中分別插入代表新vma的節點(給你家的房子被街道辦事處登記,方便日後管理)。
要注意的是,房子的分配是按照你上報的人數,但具體給你幾個房間的鑰匙(分配幾個物理頁面),取決於你家實際住進來的人數,比如你申請的是10個房間,但只住進來3個人,就只有3個房間的鑰匙,剩下的鑰匙等真正有人搬進來再給,房間資源有限,佔著不住不是浪費麼。分配的vma只是這段虛擬位址的使用權,而不是實體地址的使用權。
那是不是我申請成功10個房間,就可以保證10個人都能住進來呢?這個嘛,街道(程序)最開始也是這樣以為的,後來出現了房間申請成功,結果拿鑰匙開不了門的情況,街道就向上級管理者(核心)反映啊,這才被告知了乙個殘酷的現實:除了本條街道,還有很多條其他街道,大家處在乙個平行空間中(虛擬位址空間都是0~3gb),這70多萬個房間,其實是被所有街道共享的,誰先拿到乙個房間的鑰匙(使用物理頁面),誰才真正擁有這個房間。
一切都是假象……然後街道問上級:那你為啥一直允許我們街道上的人一口氣申請那麼多房間呢?上級若有所思的說:我當時設計這個制度啊,主要是考慮到很多人可能申請的多,但實際用不了那麼多(比如malloc(2g),但實際只用了1m),我也不知道實際誰會用的多一點,為了讓資源(這些房間)得到最充分的利用,我只能先允許他們申請著。以後這種事情多了,大家也漸漸明白,別一下申請那麼多,不合理的需求,到了上級那裡是通不過的,這種申請超過實際可用物理記憶體的現象,被稱為memory overcommit。
通過munmap()解除對映時,則需要在程序位址空間中刪除對應的vma,並釋放該vma占有的虛擬位址資源。
參考:
理解linux的memory overcommit
understanding the linux kernel
professional linux kernel architecture
understanding the linux virtual memory manager
15 分配記憶體失敗的考查
void test void 答 malloc後,應判斷 p是否null 這個題目自身有問題,深層次思考 出題人原意,free str 後,用str null杜絕野指標,但是這種寫法過於教科書化,離開這個函式,str都不能使用了,還搞個str null,不需要 在c 中,如果使用new,更不需要,參...
Kafka分割槽分配策略(4)分配的實施
2.groupcoordinator收集各個消費者的提案,然後執行以下兩個步驟 一 選舉消費組的leader 二 選舉消費組的分割槽分配策略。選舉消費組的分割槽分配策略比較好理解,為什麼這裡還要選舉消費組的leader,因為最終的分割槽分配策略的實施需要有乙個成員來執行,而這個leader消費者正好...
Linux中的0號程序和1號程序
系統允許乙個程序建立新程序,新程序即為子程序,子程序還可以建立新的子程序,形成程序樹結構模型。整個linux系統的所有程序也是乙個樹形結 構。樹根是系統自動構造的,即在核心態下執行的0號程序,它是所有程序的祖先。由0號程序建立1號程序 核心態 1號負責執行核心的部分初始化工作及進 行系統配置,並建立...