程式虛擬空間分佈

Jeff的技術棧發表於2022-03-13

程式虛擬空間分佈,全域性變數放哪裡?

1)在linux下記憶體分配是以頁為單位的,而頁是通過段管理
2)一個linux程式的虛擬地址空間分佈如上圖所示,分為使用者空間和核心空間

初始化的全域性變數分配在.data段(Section)內
未初始化的全域性變數分配在.bss段(Section)內

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)

程式碼段(.text),也叫正文段,存放程式碼

1.3.資料段(.data,.bss)

1)存放全域性變數和靜態變數

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核心程式碼段

存放核心的程式碼和資料,所有程式的核心程式碼段都對映到同樣的實體記憶體,並在記憶體中**持續存在**

2.2與程式有關的資料結構段

頁表:作業系統不是以位元組為單位管理記憶體的,而是以頁為單位管理記憶體,一頁通常為4KB。
PCB: 程式控制塊
存放程式都各自的[PCB]和[頁表],並對映到不同的實體記憶體

相關文章