動態存儲和靜態存儲
動態儲存
動態儲存是指在程序運行期間根據需要進行動態的分配
函數形參,自動變量(沒有用static聲明的變量),函數調用時的現場保護和返回地址,對以上這些數據,在函數調用開始時分配動態存儲空間,函數結束時釋放這些空間,這種分配和釋放,是動態的,如果在一個程序中兩次調用同一個函數,則分配的局部變量的儲存空間可能是不相同的
靜態儲存
靜態儲存是指在程序運行期間由系統分配固定的存儲空間
全局變量和靜態變量(用static聲明的變量)全部存放在靜態存儲區中,在程序開始執行時,給變量分配存儲區,程序執行完畢才釋放
內存佈局
一個可執行程序沒有加載到內存前(運行前),可執行程序內部已經分好3段信息,分別爲代碼區(text)、初始化數據區(data)和未初始化數據區(bss)
通過命令:size 可執行程序名 即可查看
初始化數據區(data)和未初始化數據區(bss)有時並稱爲靜態區或全局區
- 代碼區(text)
代碼區用於存放程序指令,主要是二進制代碼 - 靜態區或全局區(初始化數據區(data)和未初始化數據區(bss))
靜態區或全局區中存放未初始化的數據、已經初始化了的數據、字符串常量(只有分配空間的數據纔可以使用,沒有分配空間的數據無法使用)
初始化的數據
1.初始化的全局變量
2.初始化的靜態全局變量
3.初始化的靜態局部變量
未初始化的數據
1.未初始化的靜態局部變量,該變量系統默認值爲0
2.未初始化的全局變量,該變量系統默認值爲0
3.未初始化的靜態全局變量,該變量系統默認值爲0
字符串常量
C語言對字符串是按字符數組來處理的,在內存中開闢了一個字符數組,用來存放該字符串常量,但是這個字符數中是沒有名字的,只能通過指針變量來引用
- 棧區(stack)當程序執行過程中,由程序自動開闢的額外空間,由編譯器自動分配釋放 ,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。
局部變量、數組、結構體、指針變量、枚舉、函數形參均在棧中存儲
申請
只要棧的剩餘空間大於所申請空間,系統將爲程序提供內存,否則將報異常提示棧溢出。
在Windows下,棧是向低地址擴展的數據結構即地址分配由高向低,是一塊連續的內存的區域。
棧頂的地址和棧的最大容量是系統預先規定好的,在WINDOWS下,棧的大小是2M(也有的說是1M,總之是一個編譯時就確定的常數),如果申請的空間超過棧的剩餘空間時,將提示overflow,能從棧獲得的空間較小。
內容
在函數調用時,第一個進棧的是主函數中後的下一條指令(函數調用語句的下一條可執行語句)的地址,然後是函數的各個參數,在大多數的C編譯器中,參數是由右往左入棧的,然後是函數中的局部變量。注意靜態變量是不入棧的。
當本次函數調用結束後,局部變量先出棧,然後是參數,最後棧頂指針指向最開始存的地址,也就是主函數中的下一條指令,程序由該點繼續運行。
- 堆區(heap)一般由程序員分配釋放, 若程序員不釋放,程序結束時可能由OS(操作系統)回收 。注意它與數據結構中的堆是兩回事,分配方式倒是類似於鏈表
申請
首先應該知道操作系統有一個記錄空閒內存地址的鏈表,當系統收到程序的申請時,會遍歷該鏈表,尋找第一個空間大於所申請空間的堆結點,然後將該結點從空閒結點鏈表中刪除,並將該結點的空間分配給程序
另外,對於大多數系統,會在這塊內存空間中的首地址處記錄本次分配的大小,這樣,代碼中的delete(c++)/free©語句才能正確的釋放本內存空間。
另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鏈表中。
堆是向高地址擴展的數據結構,是不連續的內存區域。這是由於系統是用鏈表來存儲的空閒內存地址的,自然是不連續的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限於計算機系統中有效的虛擬內存。由此可見,堆獲得的空間比較靈活,也比較大。
內容
一般是在堆的頭部用一個字節存放堆的大小。堆中的具體內容有程序員安排。