一、記憶體中的程式: 在進程被載入記憶體中時,基本上被分成許多小的節,以下是6個主要的節。 低地址 高地址 .text 節 .text節基本上相當於二進位可執行文件的.text部分,它包含了完成程式任務的機器指令。 該節標記為只讀,如果發生寫操作,會造成 segmentation fault。 在進程最 ...
一、記憶體中的程式:
在進程被載入記憶體中時,基本上被分成許多小的節,以下是6個主要的節。
低地址 高地址
.text 節
.text節基本上相當於二進位可執行文件的.text部分,它包含了完成程式任務的機器指令。
該節標記為只讀,如果發生寫操作,會造成 segmentation fault。
在進程最初被載入到記憶體中開始,該節的大小就被固定。
.data 節
.data節用來存儲初始化過的變數
如: int a = 0;
該節的大小在運行時是固定的。
.bss 節
棧下節 (below stack section)用來存儲未初始化的變數
如: int a;
該節的大小在運行時是固定的。
堆 節(空閑存儲器)
堆節(heap section)用來存儲動態分配的變數,位置從低地址向高地址增長。
記憶體的分配和釋放通過malloc()和free()函數控制。
棧 節
棧節(stack section)用來跟蹤函數調用(可能是遞歸),在大多數系統上從記憶體的高地址向低地址增長。
環境/參數 節
環境/參數節(environment/ arguments section)用來存儲系統環境變數的一份複製文件,進程在運行時可能需要。
例如,運行中的進程可以通過環境變數來訪問路徑、shell名稱、主機名等信息。該節是可寫的。
命令行參數也保存在該區域中。
二、緩衝區
緩衝區(buffer)是指這樣一個存儲區域:該區域用來接收和保存數據,直至進程對數據進行處理。由於各進程都有緩衝區,
所以保持各進程緩衝區彼此無關是很重要的。通過在進程記憶體的 .data 和 .bss 節分配記憶體,可以做到這一點。
三、析構函數
如果類沒有定義自己的析構函數,編譯器會生成預設的析構函數。
預設的析構函數不能刪除在 堆(空閑存儲器)上分配的對象和對象成員。
因此,如果成員占用的空間是在構造函數中動態分配的,就必須自定義析構函數,然後釋放以前分配的記憶體。
使用C++智能指針,將自動刪除空閑存儲器中不再需要的記憶體。
1 class CMessage 2 { 3 private: 4 char * m_pMessage; 5 6 public: 7 void showIt()const 8 { 9 cout << m_pMessage << endl; 10 } 11 12 CMessage(const char* text="Default message") 13 { 14 size_t length{strlen(text)+1}; 15 m_pMessage = new char[length+1]; 16 strcpy_s(m_pMessage,length+1,text); 17 } 18 19 ~CMessage() 20 { 21 cout << "Destructor called" << endl; 22 delete[]m_pMessage; 23 } 24 }; 25 26 int main() 27 { 28 CMessage motto{"Amiss is as good as a mile"}; 29 CMessage *pM{ new CMessage{"A cat can look at a queen"} }; 30 31 motto.showIt(); 32 pM->showIt(); 33 34 delete pM; 35 36 return 0; 37 }
運行結果:
Amiss is as good as a mile
A cat can look at a queen
Destructor called
Destructor called
現在註釋掉: // delete pM;
運行結果:
Amiss is as good as a mile
A cat can look at a queen
Destructor called
編譯器為 motto 調用析構函數,是因為雖然該對象的數據成員占用的記憶體是由構造函數在堆上分配的,但它只是一個普通的自動對象。
而 pM 在堆上為該對象分配記憶體,因此必須用 delete 刪除此對象。
當使用 delete 操作符刪除動態創建的對象時,delete 操作符將在釋放該對象占用的記憶體之前,首先調用該對象的析構函數。