c++對象模型

 

C++對象模型

很久之前就想總結一下C++的內存使用機制。直到現在剛考完試之制,去實習之前,纔有時間完成這事。
1.程序使用內存區
 一個程序佔用的內存區一般分爲5種:
 (1)全局、靜態數據區:存儲全局變量及靜態變量(包括全局靜態變量和局部靜態變量)
 (2)常量數據區:存儲程序中的常量字符串等。
 (3)代碼區:存儲程序的代碼。
 (4)棧:存儲自動變量或者局部變量,以及傳遞的函數參數等。
 (5)堆:存儲動態產生的數據。
    在處理內存時,系統會自動將內存對齊,這樣雖然會浪費一些內存,但由於CPU在對齊方式下運行比較快,所以
    一般都是對程序性能還是有好處的。
 一個程序使用的棧的大小是固定的,由編譯器決定。一般是1MB。
 棧的內存是系統自動分配的,壓棧和出棧都有相應的指令進行操作。因此效率較高,並且分配的內存空間是連
 續的,不會產生內存碎片;而堆上的內存是由開發人員來動態分配和回收的。在分配內存時,系統需要按照一定
 的算法在堆空間中尋找合適大小的空閒堆,並修改相應的維護堆空閒空間的鏈表,然後返回地址給程序。因此效
 率比棧要低,此外還容易產生內存碎片。
 從C++對象模型的角度來說,對象就是內存中的一片區域。如果一個對象通過定義在某個函數內的變量或者實現
 需要的臨時變量來創建時,它是棧上的一個對象;如果一個對象是定義在全局範圍內的變量,則它是存儲全局/靜
 態數據區;如果一個對象是通過new操作符來創建時,它是堆上的一個對象。
2.對象的生命週期
 (1)通過定義變量創建對象:在這種情況下,變量的作用域決定了對象的生命週期。當進入變量的作用域時,對
 象被創建。而退出變量的作用域時,對象被銷燬。值得注意的是靜態變量和全局變量,由於全局變量的作用域是整
 個程序,因此被聲明爲全局變量的對象在程序調用main()函數之前被創建。當程序退出main()函數之後,全局對象
 才被銷燬。靜態對象與全局對象類似,雖然靜態變量的作用域不是整個程序,但靜態變量是存儲在全局/靜態數據區
 中,在程序開始時已經分配好。因此聲明爲靜態變量的對象第一次進入作用域時被創建,直到程序退出時被銷燬。
 (2)通過new操作符創建對象:這種情況相對比較簡單,但也最容易造成內存泄漏。通過new創建的對象會一直存在,
 直到被delete銷燬。即使指向該對象的指針(一般都是自動變量)已被銷燬,但還沒有調用delete,該對象就會一直
 存在。即佔據內存空間,直到程序退出,因此也就造成內存泄漏。
 (3)通過實現創建對象:這種情況一般是指一些隱藏的中間臨時變量的創建和銷燬。它們的生命週期很短,也不容易
 被開發人員發覺。但常常是造成程序性能下降的瓶頸,尤其是對於那些佔用內存較多,創建速度較慢的對象。這些臨時
 對象一般是通過copy constructor創建的。在實際開發中,通過值傳遞傳遞參數,重載+及++等操作符,對對象進行算術
 運算時,也會有臨時對象,對於這些情況,都要儘量避免不必要的臨時對象的出現。
3.C++對象的內存佈局
 (1)非靜態數據成員是影響對象佔據內存大小的主要因素,隨着對象數目的增加,非靜態數據成員佔據的內存會相應增加。
 (2)所有的對象共享一份靜態數據成員,所以靜態數據成員佔據的內存的數量不會隨着對象數目的增加而增加。
 (3)靜態成員函數和非靜態成員函數不會影響對象內存的大小,雖然其實現會佔據相應的內存空間,同樣也不會隨着對象
 數目的增加而增加。
 (4)如果對象中包含虛函數,會增加4個字節的空間(虛函數表指針),不論有多少個虛函數
類的靜態函數只有一個實例,同樣的,非靜態成員函數也是一個實例,無論是否創建該類的對象,靜態、非靜態函數都存在。 
std::ostream並沒有對void(__thiscall A::*)()類型重載 < <操作符,編譯器將這種類型轉換爲bool類型,因此輸出爲1(或0),而靜態函數並非__thiscall,而是__cdecl,std::ostream有對它的重載,因此類的靜態函數可以直接用cout輸出函數地址。 
printf可以接收任意類型的參數,包括__thiscall類型的類成員函數,因此它可以輸出該種函數地址

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章