c語言和內存
A. C語言:關於動態內存的復習總結(分配器)
C語言中動態內存管理是程序員必須掌握的重要知識點,主要涉及內存的三個區域:棧區、堆區和數據區。其中,棧區主要存放局部變數,函數調用結束後自動釋放;堆區由malloc或new動態分配,需要程序員手動釋放,未釋放的內存會持續存在直到程序結束;數據區則包含全局變數和靜態變數,其生命周期與程序同進退。
在內存操作中,常見的問題包括:未給指針分配合法內存、分配空間不足、未初始化、指針越界和內存泄漏。動態內存分配器如malloc和free,維護進程的虛擬內存堆,分為顯示分配器(如C語言)和隱式分配器(如垃圾收集器)兩種模式,前者需要顯式釋放,後者負責自動回收不再使用的內存。
動態內存分配的目標是滿足程序運行時對內存大小的不確定性,避免空間浪費或不足。分配器需要滿足一系列要求,如處理任意請求、不修改已分配內存、只在堆區分配等,以最大化吞吐率和內存利用率。實現動態內存分配器時,會面臨空閑塊組織、放置策略和內存合並等問題,如隱式空閑鏈表就通過頭尾信息來連接空閑塊,雖然簡單但搜索效率低。
顯示空閑鏈表則是將空閑內存塊組成一個獨立的鏈表,相比隱式鏈表,它在首次適配時的時間復雜度更低,釋放和合並操作也有特定的優勢。掌握這些概念和操作,可以幫助程序員更好地管理內存,提高代碼的健壯性和效率。
B. C語言 + 單片機-內存分布詳解
C語言內存分區示意圖如下:
1. 代碼區
2. 常量區
3. 全局(靜態)區
.bss段
.data段
4. 堆區(heap)
調用函數參數size_t是分配的位元組大小,返回值是一個void型的指針,該指針指向分配空間的首地址。參數是開辟的內存的首地址。
5. 棧區(stack)
在STM32中,內存分配如下:
1. 隨機存儲器—RAM
2. 只讀存儲器—ROM
STM32F103晶元的內部分區如下圖所示。
編譯程序完成後,可以看到編譯後的大小信息,包括Code、RO-data、RW-data和ZI-data的大小。這有助於開發人員和嵌入式系統設計者更好地管理內存資源並確保程序在目標設備上正常運行。
Code:代碼段,指程序由編譯器生成的可執行的機器指令。
RO-data:數據段,指程序中的只讀數據部分,包括常量、字元串、const定義的變數等。
RW-data:數據段,指初始化為「非0值「的可讀寫數據,程序運行的時候這些數據又會常駐在RAM區,應用程序可以修改其內容。包括初始化為非零的全局變數和靜態變數。
ZI-data:數據段,指初始化為0值的可讀可寫數據,它與RW-data的區別是程序剛運行時這些數據初始值全都為0,程序運行時和RW-data的性質一樣,它們也常駐在RAM區,應用程序可以更改其內容。包括未初始化和初始化為零的全局變數和靜態變數。
ZI-data 的棧空間(Stack)及堆空間(Heap):在C語言中,函數內部定義的局部變數屬於棧空間,而使用malloc動態分配的變數屬於堆空間。在程序中的棧空間和堆空間都是屬於ZI-data區域的,這些空間都會被初始值化為0值。
關於哪些數據存儲在Flash區域,哪些數據存儲在SRAM區域,這涉及到程序的存儲狀態。程序具有靜止和運行兩種狀態,靜止態的程序被存儲在非易失存儲器中,如內部FLASH區域。當程序在運行狀態的時候,程序常常需要修改一些暫存數據,這些數據往往存放在Flash中,但需要被復制到RAM中。
程序存儲分布如下圖展示。當程序存儲到晶元的內部FLASH時,它佔用的空間為Code+RO-data+RW-data的總和。程序在執行的時候,需要佔用內部SRAM空間,佔用的空間為RW-data+ZI-data之和。
結論,想要讓一個程序正常運行,必須滿足以下兩個條件:程序編譯後打開工程的map文件,在map文件的最後一段也可以看到ROM的總大小。
劃分依據及好處:首先區分代碼段和數據段。程序源代碼編譯後的機器指令放在代碼段;數據段包括" .data "、" .bss "、" .rodata ",將程序中定義的全局變數和局部變數都稱為數據段。
把程序的「代碼段」和「數據段」分開存放,數據和指令分別被映射到兩個虛擬內存區域,數據段對進程是可讀寫的,而代碼段對進程是只讀的。現代CPU緩存設計成數據緩存和指令緩存分離,程序的指令和數據分開存放提高緩存命中率。
數據段還需要分 ".data"、".bss"、".rodata",主要根據是否占內存空間、讀寫許可權進行區分。".data"段和".bss"段都是可讀寫的數據段,而".rodata"存放的是只讀數據,主要是一些const變數和字元串常量。".rodata"段單獨設立的好處是可以將屬性映射成只讀,減少修改操作,還可以將".rodata"段存放在只讀存儲器中。
全局變數也有細分初始化和未初始化,把全局變數分開存放,初始化為0和未初始化的全局變數放在BSS區,初始化不為0的全局變數存放在數據區。程序有兩個存儲狀態,靜止狀態的程序被存儲在非易失存儲器中,運行狀態的程序需要修改一些暫存數據存放在內存中,減少從ROM讀數據的次數提高效率。
C. 詳細講解C語言五大內存分區與可執行程序的三段(Text段、Date段、Bss段)【建議收藏】
本文詳細講解C語言五大內存分區與可執行程序的三段(Text段、Data段、Bss段)。
首先,C語言五大內存分區包括:靜態內存、動態內存、棧內存、堆內存和文件I/O內存。靜態內存用於存儲全局變數和靜態變數,動態內存由new和malloc函數分配,棧內存用於函數調用時的局部變數和函數參數,堆內存用於動態分配和管理,文件I/O內存用於文件讀寫操作。
其次,可執行程序的三段分別為:Text段、Data段、Bss段。Text段存儲了程序的機器代碼,Data段存儲了程序的全局變數和靜態變數的初始值,Bss段用於存放未初始化的全局變數和靜態變數。Text段和Data段是只讀的,而Bss段是可讀可寫的。
在可執行程序內存空間與邏輯地址空間的映射與劃分上,執行文件通常被映射到進程的邏輯地址空間中。執行文件的文本、數據和Bss段分別映射到進程的文本、數據和Bss段。
接著,存儲類型關鍵字定義了變數的存儲類型,如static、extern、auto和register。這影響了變數的作用域和生命周期。靜態變數在全局或文件級作用域中,其生命周期在程序運行期間一直存在;外部變數在文件級作用域中,其值在程序運行期間始終存在;自動變數在函數作用域中,其值在函數調用結束後釋放;寄存器變數在函數調用期間使用,以提高執行效率。
在堆與棧的區別上,堆和棧在申請方式、申請後的系統響應、申請大小限制、申請效率、存儲內容以及存取效率上有所不同。在運行時刻賦值的變數通常在堆中分配,而編譯時已經確定的變數通常在棧中分配。在存取效率上,棧上的數組比指針指向的字元串更快。