一杰妓、堆椩逯危基礎——內(nèi)存區(qū)域
代碼是以進程的形式來執(zhí)行的,一個進程可能被分配到不同的內(nèi)存區(qū)域去執(zhí)行:
- 代碼區(qū):這個區(qū)域內(nèi)存儲著被裝入執(zhí)行的二進制機器代碼巷挥,處理器會到這個區(qū)域取指并執(zhí)行
- 數(shù)據(jù)區(qū):用于存儲全局變量/靜態(tài)變量等
- 堆區(qū):進程可以在堆區(qū)動態(tài)的請求一定大小的內(nèi)存桩卵,并在使用完之后還給堆區(qū)。動態(tài)分配和回收是堆區(qū)的特點倍宾,是向高地址擴展的內(nèi)存區(qū)域雏节,通常由程序員來管理
-
棧區(qū):用于動態(tài)的存儲函數(shù)之間的調用關系,以保證調用函數(shù)在返回時恢復到母函數(shù)中繼續(xù)執(zhí)行高职,是由操作系統(tǒng)來管理的钩乍。
棧區(qū)
棧是向低地址擴展的數(shù)據(jù)結構,入棧時是從高地址向低地址擴展怔锌,是一塊連續(xù)的內(nèi)存的區(qū)域寥粹。通常用來存儲局部變量变过。棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預先規(guī)定好的,在windows下涝涤,棧的默認大小是2M媚狰,如果申請的空間超過棧的剩余空間,將提示overflow
堆區(qū)
堆是向高地址擴展的數(shù)據(jù)結構阔拳,是不連續(xù)的內(nèi)存區(qū)域崭孤,堆的大小受限于計算機的虛擬內(nèi)存。
操作系統(tǒng)中有一個記錄空閑內(nèi)存地址的鏈表糊肠,當系統(tǒng)收到程序的申請時辨宠,會遍歷該鏈表
- 尋找第一個空間大于所申請空間的堆結點,然后將該結點從空閑結點鏈表中刪除货裹,并將該結點的空間分配給程序
- 由于找到的堆結點的大小不一定正好等于申請的大小彭羹,系統(tǒng)會自動將多余的那部分重新放入空閑鏈表中。
-
對于大多數(shù)系統(tǒng)泪酱,會在這塊內(nèi)存空間中的首地址記錄本次分配的大小派殷,這樣代碼中的delete語句才能正確的釋放本內(nèi)存空間
區(qū)別
申請方式
棧:由系統(tǒng)自動分配。
堆:需要程序員自己申請墓阀,并指明大小毡惜,在c中malloc函數(shù) 例如p1=(char *)malloc(10)
申請效率
棧:系統(tǒng)自動分配,速度比較快斯撮,但是程序員無法控制
堆:由程序員分配的內(nèi)存经伙,一般速度比較慢,而且容易產(chǎn)生內(nèi)存碎片勿锅,不過用起來方便
二帕膜、堆棧基礎——函數(shù)調用
函數(shù)調用時溢十,將借助系統(tǒng)棧來完成函數(shù)狀態(tài)的保存和恢復
主函數(shù)中調用函數(shù)A垮刹,函數(shù)A又調用的函數(shù)B,函數(shù)B的返回值加上一個值作為函數(shù)A的返回值张弛,最后函數(shù)A的返回結果作為主函數(shù)的返回值
- 這些代碼區(qū)中精確的跳轉都是在與系統(tǒng)棧巧妙的配合過程中完成的荒典。
- 當函數(shù)被調用時,系統(tǒng)棧會為這個函數(shù)開辟一個新的棧幀吞鸭,并把它壓入棧中寺董。每個棧幀對應著一個未運行完的函數(shù)。棧幀中保存了該函數(shù)的返回地址和局部變量刻剥。從邏輯上講遮咖,棧幀就是一個函數(shù)執(zhí)行的環(huán)境:函數(shù)參數(shù)、函數(shù)的局部變量造虏、函數(shù)執(zhí)行完后返回到哪里等待御吞。
-
當函數(shù)返回時踢械,系統(tǒng)棧會自動彈出該函數(shù)所對應的的棧幀,彈出棧幀意味著這個函數(shù)執(zhí)行完畢魄藕。
函數(shù)調用的步驟
棧是先進后出的數(shù)據(jù)結構
- (1)參數(shù)入椖诹校——將參數(shù)從右向左依次壓入系統(tǒng)棧中
- (2)返回地址入棧——將當前代碼區(qū)調用指令的下一條指令地址壓入棧中背率,供函數(shù)返回時繼續(xù)執(zhí)行
- (3)代碼區(qū)跳轉——處理器從當前代碼區(qū)跳轉到被調用函數(shù)的入口(就是跳轉到被調用的函數(shù)處话瞧,再取指令時就從被調用的函數(shù)的代碼區(qū)開始取指令)
- (4)棧幀調整。取指令時寝姿,會包括棧幀調整交排。具體包括
保存當前棧幀狀態(tài)值,已備后面恢復本棧幀時使用饵筑。
將當前棧幀切換到新棧幀埃篓。
三、堆椄剩基礎——常見寄存器和棧幀
寄存器
寄存器是中央處理器CPU的組成部分架专。寄存器是有限存儲容量的高速存儲部件,它們可以用來暫存指令玄帕、數(shù)據(jù)和地址部脚。我們常常看到32位CPU裤纹、64位CPU這樣的名稱委刘,其實指的就是寄存器的大小。32位CPU寄存器大小就是4字節(jié)鹰椒。CPU越大說明CPU一次處理的數(shù)據(jù)就越多
為了緩解CPU和內(nèi)存效率不對等的問題锡移,CPU自帶一級緩存和二級緩存,但是這些緩存還是不夠快漆际,于是將一些最常訪問的數(shù)據(jù)存放在寄存器中(寄存器的讀寫速度比內(nèi)存快很多)淆珊,CPU優(yōu)先讀取寄存器,再由寄存器跟內(nèi)存交換數(shù)據(jù)灿椅。
CPU套蒂、寄存器和內(nèi)存
CPU運算所需數(shù)據(jù)只能從寄存器存取钞支,寄存器會先從高速緩存區(qū)讀取數(shù)據(jù)茫蛹,不命中才會從內(nèi)存讀數(shù)據(jù)。而內(nèi)存中的數(shù)據(jù)也是先從磁盤緩存區(qū)(disk cache)讀數(shù)據(jù)烁挟,或者在磁盤緩沖區(qū)(disk buffer)存數(shù)據(jù)婴洼,最后才會交際最慢的磁盤。
ESP和EBP兩個寄存器
棧指針寄存器ESP(extended 寄存器 stack棧 pointer指針)
ESP標識了當前棧幀的頂部(相當于top)
基址指針寄存器ESP(extended 寄存器 base基址 pointer指針)
ESP標識了當前棧的底部(相當于base)
ESP和EBP之間的內(nèi)存空間為當前幀撼嗓,當前幀指的是系統(tǒng)棧中最頂部的棧幀柬采。**
函數(shù)棧幀中包含的信息
- 局部變量
- 棧幀狀態(tài)值欢唾,用于在本幀被彈出后恢復出上一個棧幀
-
函數(shù)返回地址,以便函數(shù)返回時能夠恢復到函數(shù)被調用前的代碼區(qū)中繼續(xù)執(zhí)行指令
指針寄存器EIP(extended 寄存器 instruction pointer指針)
指針寄存器粉捻,期內(nèi)存放著一個指針礁遣,該指針永遠指向下一條等待執(zhí)行的指令地址。
函數(shù)調用完畢后肩刃,返回原來函數(shù)指令運行的一個關鍵操作是祟霍,將棧幀中保持的返回地址裝入EIP寄存器。
控制了EIP寄存器就相當于控制了進程盈包,我們讓EIP指向哪里沸呐,CPU就會去執(zhí)行哪里的指令。
之所以將ESP值裝入EBP是因為新的棧幀是位于舊的棧幀上面呢燥,所讓舊的棧幀的頂部ESP成為新的棧幀的底部EBP