關於Linux的記憶體之我的總結

2021-08-28 06:53:51 字數 1793 閱讀 8760

說來慚愧,作為一名linux應用層軟體開發人員,應當對linux的分配、布局等方式了然於胸,而我索然在之前有所了解,但總覺得是雲裡霧裡的,沒有真正搞清楚。現在也算是乙個總結吧,可能還會有錯誤,後續把《深入理解linux核心》這本書學習後,再來修改。

大家都知道,乙個linux的應用程式,擁有**段(.text段)、資料段(.data段)、bss段、堆、棧這五個段。

其中,資料段和bss段的區別是,資料段中存放的是已經初始化過的全域性變數和靜態變數,而bss段中放的是未經初始化的全域性變數和靜態變數。當有應用程式載入到記憶體後,發現bss段中有資料,則會在分配一塊堆空間,將bss段中的資料移動至堆裡,並將其全部賦值為0。

有下面這個小例子:

上圖和下圖當中,唯一的區別就是上圖沒有把test[1024000]這個陣列給賦值,而下圖將陣列賦值了,但編譯出來的大小可以看到,這兩個程式的大小正好是1024000位元組,也就是這個陣列的大小。這說明了資料段是會在編譯出來的程式中占用空間,而bss段則不會。

首先見下圖(網上找了張):

大家都知道,linux的每個程序,在32位的情況下,擁有4g的虛擬記憶體。其中0-3g是屬於使用者態記憶體,而3-4g是核心態的記憶體。

如上圖可以看出,從0位址往上增加的過程中,首先存放的是唯讀段資料,比如剛才所說的程式段、常量資料等,然後就到了資料段和bss段的可讀寫區域。在可讀寫資料區域的上面,是堆區域,而最靠近核心態記憶體區域的是棧空間。堆和棧空間之間的區域,是檔案對映區域。

關於上面的描述,我見到過乙個面試題,記錄在這裡:

int main (int argc, char **argv)

求問,由&a, &b, c, &d排個大小順序。

根據前面看到的程序記憶體布局可以知道,a是存在於棧空間的,它的位址屬於最高,也就是說&a為最大,而b處於可讀寫的資料段中,c處於堆空間中,&d處於唯讀資料區域。

所以&a > c > &b > &d。

linux在執行的時候,使用者態程式使用malloc來進行記憶體分配。而malloc是乙個c庫實現的程式,他的底層分為兩種情況:

在malloc小於128kb以內的記憶體時,系統呼叫brk()或sbrk()進行記憶體分配,此時記憶體是在堆中往上增加。此時不需要陷入到核心進行記憶體分配,效能最強。但也有缺點:那就是會出現洩漏的問題,具體是因為,以brk方式分配記憶體,只是把堆的指標向上移動得到新的虛擬記憶體。當多次分配記憶體後,想釋放中間的記憶體,由於上面的記憶體還在使用中,故不可釋放,只是將其標記為可用,下次還需要申請時,會從此處分配。當中間記憶體的上面區域被釋放後,此時該記憶體才會真正被釋放掉。所以有時候會看到,申請記憶體或釋放記憶體後,vsz並沒有增大或者減小。而當多次申請和釋放小記憶體時,會有記憶體洩漏問題,而此時是無法使用valgrind工具檢測到。

在malloc大於128kb以內的記憶體時,系統其實是呼叫malloc()來進行記憶體的分配,此時記憶體分配區域處於棧和堆中間的檔案對映區。這種記憶體分配的好處就是每次申請和釋放,都能做到真正的記憶體操作,而不會造成記憶體碎片問題。缺點就是,每次分配時,需要陷入到核心態,進行記憶體分配,效能開銷比較大。

另外要說明的是,malloc分配記憶體時,是先分配好虛擬記憶體,建立好頁表而已,當應用程式需要使用到此塊記憶體時,陷入到核心態,建立起真正的虛擬記憶體到真實物理記憶體的對映關係。

關於linux記憶體的管理

1 最近又稍微看了linux記憶體的管理,又稍微有一點收穫,來這裡記錄一下,以防以後又忘記了。都是針對32位的線性位址 首先是linux核心中從邏輯位址到實體地址的轉化。由於x86要支援段式對映,l段式對映是將段描述符中的基位址加上偏移量的定址方式。ldtr或者gdtr暫存器指向段描述符表的首位址,...

我的2011 2011之總結

我的2011 2011之總結 2011年馬上就要過去,傳說中的2012就要來了,這裡對2011做乙個簡短的總結。從昨天參與組織的元旦晚會落幕,我就知道,我真的該向研究生會說再見了,看到那麼多的熟悉的面孔 能人,我真應該放心的退出了。也是真的是到了對2011年該說再見的時候了,2011讓人難忘。參與師...

關於記憶體對齊的小總結

對齊規則 1 資料成員對齊規則 結構 struct 或聯合 union 的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的對齊按照 pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。2 結構 或聯合 的整體對齊規則 在資料成員完成各自對齊之後,結構 或...