1)在linux下內存分配是以頁為單位的,而頁是通過段管理
2)一個linux進程的虛擬地址空間分布如上圖所示,分為用戶空間和內核空間,對於一個32位操作系統來說,4GB的空間分成兩部分,低地址的0~3G給用戶空間,高地址的3G~4G給內核空間
1.用戶空間
1.1只讀數據段(也叫常量段,.rodata,Read Only之意,未在圖中標出)
1)存放只讀數據:字符串常量(如"hello")和const修飾的全局變量
2)不是所有的只讀數據都是放在只讀數據段,有些可以通過立即數(在立即尋址方式指令中給出的數稱為立即數;立即尋址方式:操作數緊跟在操作碼的后面,與操作碼一起放在指令代碼中)來實現的常量(如“int i=5”中的“5”)不存放在只讀數據段,而是直接編碼在指令里,存放在在正文段
3)const修飾的全局變量是存放在常量段的,但是使用const修飾的局部變量不存放在常量段,存放在棧段
4)對於字符串常量,編譯器會在常量段中自動去重,讓每種字符串常量只有一份
5)為了提高空間的利用率,有些系統中.rodata段是多個進程共享的
6)程序加載運行時,.rodata和.text通常合並到一個段(Text Segment)中,操作系統將這個段只讀保護起來,防止意外的改寫
1.2代碼段(.text)
,也叫正文段,存放代碼
1.3.數據段
2)初始化數據段(.data):存放已經初始化的
3)未初始化數據段(.bss):存放未初始化的
4).data和.bss在程序加載時合並到一個段(Data Segment)中,這個段是可讀可寫的
5)c++不區分初始化的和未初始化的,它們占同一塊區域
1.4.堆
動態內存的分配
1.5.內存映射段
1)常被用來加載共享庫(動態庫)
2)內存映射:將虛擬內存空間與磁盤上的文件關聯起來,這個過程叫內存映射
1.6.棧
存放局部變量
1.7棧與堆的區別
1)管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程序員控制,容易產生內存泄露
2)空間大小:一般來講在32位系統下,堆內存可以達到3G的空間(4G有1G要給內核);而棧的最大容量是事先規定好的(例如,在VC6下面,默認的棧空間大小是1M,可修改)
3)碎片問題:對於堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低;對於棧來講,則不會存在碎片,因為棧是先進后出的結構,一個內存塊要從棧中彈出,在它上面的后進的內存塊肯定要先被彈出
4)生長方向:對於堆來講,生長方向是向上的,也就是向着內存地址增加的方向;對於棧來講,它的生長方向是向下的,是向着內存地址減小的方向增長;
5)分配方式:堆都是動態分配的;而棧有2種分配方式:靜態分配和動態分配,靜態分配是編譯器完成的,比如局部變量的分配,動態分配由alloca函數(類似於malloc,專門在棧中申請空間的函數)進行分配,但是即使是動態分配,它也和堆是不同,棧的動態分配是由編譯器進行釋放,無需我們手工釋放
6)分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高;堆則是C/C++函數庫提供的,它的機制是很復雜,例如:為了分配一塊內存,庫函數會在堆內存中搜索連續的足夠大小的空間,如果沒有足夠大的空間(可能是由於內存碎片太多),就需要操作系統重新整理內存空間,這樣就有機會分到足夠大的內存,然后進行返回。顯然,堆的效率比棧要低得多
2.內核空間
2.1內核代碼段
存放內核的代碼和數據,所有進程的內核代碼段都映射到同樣的物理內存,並在內存中持續存在