前言
看了些Linux內存管理的文章,寫一寫加深對內存管理的印象。
正文
程序的存儲
ELF是Linux的主要可執行文件格式。ELF文件由4部分組成,分別是ELF頭(ELF header)、程序頭表(Program header table)、節(Section)和節頭表(Section header table)。具體如下:
- Program header描述的是一個段在文件中的位置、大小以及它被放進內存後所在的位置和大小。即要加載的信息;
- Sections保存着object 文件的信息,從連接角度看:包括指令,數據,符號表,重定位信息等等。在圖中,我們可以看到Sections中包括:
- text 文本結 存放指令;
- rodata 數據結 readonly;
- data 數據結 可讀可寫;
- Section頭表(section header table)包含了描述文件sections的信息。每個section在這個表中有一個入口;每個入口給出了該section的名字,大小,等等信息。相當於 索引!
代碼編譯和存儲
Linux 虛擬地址空間如何分佈?
Linux 使用虛擬地址空間,大大增加了進程的尋址空間,由低地址到高地址分別爲:
- 只讀段:該部分空間只能讀,不可寫;(包括:代碼段、rodata 段(C常量字符串和#define定義的常量) )
- 數據段:保存全局變量、靜態變量的空間;
- 堆 :就是平時所說的動態內存, malloc/new 大部分都來源於此。其中堆頂的位置可通過函數 brk 和 sbrk 進行動態調整。
- 文件映射區域:如動態庫、共享內存等映射物理空間的內存,一般是 mmap 函數所分配的虛擬地址空間。
- 棧:用於維護函數調用的上下文空間,一般爲 8M ,可通過 ulimit –s 查看。
- 內核虛擬空間:用戶代碼不可見的內存區域,由內核管理(頁表就存放在內核虛擬空間)。
下圖是 32 位系統典型的虛擬地址空間分佈(來自《深入理解計算機系統》)。
char *a 與char a[] 的區別
char *d = “hello” 中的d是指向第一個字符‘h’的一個指針;char s[20] = “hello” 中數組名s也是指向第一個字符’h’的指針。現執行下列操作:strcat(d, s)。把字符串加到指針所指的字串上去,出現段錯誤。本質原因:*d="hello"存放在常量區,是無法修的。而數組是存放在棧中,是可以修改的。
兩者區別如下:
讀寫能力:char *a = "abcd"此時"abcd"存放在常量區。通過指針只可以訪問字符串常量,而不可以改變它。而char a[20] = “abcd”; 此時 "abcd"存放在棧。可以通過指針去訪問和修改數組內容。
賦值時刻:char *a = "abcd"是在編譯時就確定了(因爲爲常量)。而char a[20] = “abcd”; 在運行時確定
存取效率:char *a = “abcd”; 存於靜態存儲區。在棧上的數組比指針所指向字符串快。因此慢,而char a[20] = "abcd"存於棧上,快。
另外注意:char a[] = “01234”,雖然沒有指明字符串的長度,但是此時系統已經開好了,就是大小爲6-----‘0’ ‘1’ ‘2’ ‘3’ ‘4’ ‘5’ ‘\0’,(注意strlen(a)是不計’\0’)
結束
初步瞭解了程序的存儲結構和運行結構。分享給和我一樣還不太瞭解的朋友。一步一個腳印 . . .
參考:
linux環境內存分配原理 mallocinfo
Linux系統內存管理
Linux內存管理(最透徹的一篇)
Linux C 內存管理
深入理解C語言內存管理