2012年2月15日 星期三

linux記憶體管理-VMA (Virtual Memory Address)

可執行檔案ELF被切割成很多section,對應不同的作用,其中包含symbol table,有的用來輔助記憶體定位,可是還沒有接觸到實際定位
先談談linux對記憶體的處理方式,linux將記憶體先分成兩部分,一部份是保留給kernel使用的1G,其餘是給user space,在32 bit的address line下是1G/3G(PAE case暫時不考慮),跟著這些使用者可以使用的記憶體再切成4k/2M大小區塊稱為page,這就是最基本單位,就類似某個國家硬幣最小就是4k/2M,沒有再小的單位了,雖然有2k,但也只是存款簿上的數字或者單純數字上。

核心就控制著如何把實體的記憶體配置給process,這中間有個單元叫做MMU,專職處理這樣的事情,跟著為了安全性找想,linux對process引入一個虛擬的區塊,一個可以使用的3G記憶體區塊稱Process Virtual Space,是一個邏輯上假的3G連續的記憶體,也就是實際上你需要的時候再配置空間給你,而且process的記憶體空間邏輯上雖然是連續,可是實際上未必。比方說process有個16k的陣列資料,在邏輯上他是連續的(0x00000000~00004000),但是經過MMU的手段之後,他可能佔據實際記憶體中的1,5,8,22這四個pages。這樣做有兩個好處,process可以專心在程式邏輯,不用管理位置如何應對,這部分委託給MMU,同時process因為接觸不到實體位置,他也不可能亂寫資料寫到別的process所用的位置。

ELF被loader載入成為程式(進入記憶體)的時候,他使用的 Process Virtual Space 的位置就是VMA (Virtual Memory Address),這時候.txt可能會被放在3G上面任何一個起始位置,跟著所有符號(如function name),根據這個位置做修正。那麼loader要如何將這些記憶體放置在記憶體中面臨到兩個問題,第一個section很多,載入很花時間,另外很多section很小,對於4k的page會浪費很多空間,比方說只有1k就要配置1 page,6k要配置2 pages。

所以loader引入了segment的觀念,segment將屬性相同的sections整理看成單一區塊,對應成相同的VMA區塊,例如有3個唯獨的sections大小分別為5, 3, 5 k,那麼視為VMA0,分配4個pages,另外可讀寫的2, 5, 7 k三個sections,視為VMA1分配4 pages,這樣一來就loader只要單存看屬性,簡單地分成6種左右的segment,不用處理一大堆的sections,也可以省下記憶體空間(如果是用section為單位配置分頁,一共要2+1+2跟1+2+2,總共10 pages)。下圖是elfread -l b.out的結果,可以看到整個elf被當成了6個segments,相同的segment有類似的屬性

上面是Process Virtual Space處理的方式,可是MMU在幫忙應對到實際記憶體的時候,更加的"吝嗇",記憶體是很寶貴的資源,屬於所有process共有,所以只好再請你們擠一下,將兩個segments對應到連續空間,就可以用9 pages擠進所有分配

所以記憶體的管理從ELF(sections)=>Process Virtual Space(loader)=>Physical(MMU)

沒有留言:

張貼留言