機(jī)器運行的是本地代碼(Native Code)
用某種編程語言編寫出來的程序是源代碼,保存源代碼的文件是源文件裕便。源文件只是文本文件寂嘉,并不能直接運行,因為CPU只能運行本地代碼(機(jī)器語言代碼)侄刽。因此,源代碼必須被轉(zhuǎn)換為本地代碼拓挥。
本地代碼里有什么唠梨?
Window中.EXE文件的程序內(nèi)容袋励,就是本地代碼侥啤。只有機(jī)器能夠理解,人不能理解茬故。
將它DUMP一下盖灸,即每字節(jié)以2位16進(jìn)制(2進(jìn)制和16進(jìn)制的轉(zhuǎn)換規(guī)則中,二進(jìn)制中每4位可以轉(zhuǎn)換為十六進(jìn)制中1位)的形式表現(xiàn)磺芭,就可以發(fā)現(xiàn)赁炎,本地代碼其實是數(shù)值的集合。每一個數(shù)值都代表了一個命令或一個數(shù)據(jù)钾腺。
從源文件到可執(zhí)行文件的過程
第一步:轉(zhuǎn)換源代碼:編譯器
編譯器:將編程語言編寫的源代碼轉(zhuǎn)換為本地代碼的程序徙垫。
編譯完成的程序為 .obj 目標(biāo)文件 ,內(nèi)容是本地代碼放棒。但是還不能夠運行姻报。轉(zhuǎn)換每種高級編程語言都需要其專有的編譯器,例如C語言的C編譯器间螟。
同種編程語言在不同CPU下的編譯器也不同吴旋。
編譯器也是程序损肛,因此也需要適合它的運行環(huán)境。
因此荣瑟,確定一個編譯器的種類治拿,需要確定哪種編程語言+哪種CPU+哪種運行環(huán)境。而實際上購買和下載時笆焰,通常指需要確定編譯器產(chǎn)品名稱+版本號即可劫谅。
第二步:生成.EXE文件與啟動:鏈接器
經(jīng)過編譯器的編譯,源文件已經(jīng)被轉(zhuǎn)換成了.obj 目標(biāo)文件嚷掠。
鏈接:將多個目標(biāo)文件結(jié)合起來同波,生成一個.EXE 可執(zhí)行文件。
鏈接器:運行鏈接的程序叠国。
庫文件和標(biāo)準(zhǔn)函數(shù)
庫文件未檩,即.lib文件,是指將多個目標(biāo)文件集成保存在一個文件里的形式粟焊。
標(biāo)準(zhǔn)函數(shù):在庫文件中收錄的函數(shù)冤狡。在程序中,不通過源代碼另行編寫项棠,而通過庫文件提供的函數(shù)悲雳。
如果主程序中使用了標(biāo)準(zhǔn)函數(shù),在運行鏈接程序時香追,鏈接器就需要指定收錄它的庫文件合瓢,將庫文件中需要的.obj目標(biāo)文件(包含此標(biāo)準(zhǔn)函數(shù))抽取出來,與其他目標(biāo)文件共同生成一個.EXE可執(zhí)行文件透典。
啟動
在鏈接時晴楔,必須鏈接一個特殊的目標(biāo)文件,它記述了同所有程序起始位置相結(jié)合的處理內(nèi)容峭咒,成為程序的啟動税弃。
DLL文件和導(dǎo)入庫
靜態(tài)鏈接庫:
靜態(tài)鏈接庫中包含了目標(biāo)文件的實體,包含了主程序中使用的標(biāo)準(zhǔn)函數(shù)的具體代碼凑队,在鏈接時则果,直接與目標(biāo)文件結(jié)合。
導(dǎo)入庫(.lib)
導(dǎo)入庫文件中漩氨,不包含目標(biāo)文件的實體西壮,而只包含了:1.被調(diào)用的標(biāo)準(zhǔn)函數(shù)位于哪個DLL文件中;2.這個DLL文件所在的文件夾信息。
在鏈接時叫惊,只提供此標(biāo)準(zhǔn)函數(shù)的被調(diào)用信息參與鏈接款青。
動態(tài)鏈接庫(.dll)
動態(tài)鏈接庫中包含了目標(biāo)文件的實體,在程序運行時赋访,動態(tài)地與.EXE可執(zhí)行文件結(jié)合可都。
總結(jié)
.EXE文件的運行機(jī)制
EXE作為單獨的文件被儲存在磁盤中缓待,被雙擊打開時,被加載到內(nèi)存中渠牲,由CPU運行旋炒。
EXE程序中的變量和函數(shù),是怎樣確定在內(nèi)存中的地址的签杈?
EXE文件給變量和函數(shù)分配了虛擬的內(nèi)存地址瘫镇。鏈接時,鏈接器在EXE文件的開頭追加了轉(zhuǎn)換內(nèi)存地址的必要信息答姥。程序運行時铣除,根據(jù)這個信息(稱為再配置信息),將虛擬內(nèi)存地址轉(zhuǎn)換為真實內(nèi)存地址鹦付。
方式:EXE程序給變量和函數(shù)分配的虛擬內(nèi)存地址尚粘,作為真實內(nèi)存地址的基點存在。鏈接器追加的再配置信息敲长,作為相對地址存在郎嫁,即相對基點地址的偏移量。
真實內(nèi)存地址=基點地址+相對地址祈噪。
堆和棧
EXE文件的內(nèi)容分為再配置信息泽铛、函數(shù)組合變量組。
加載到內(nèi)存后辑鲤,還會再生成兩個組:堆和棧盔腔。
棧:儲存函數(shù)參數(shù)和局部變量的內(nèi)存區(qū)域。
堆:儲存程序運行時任意對象和數(shù)據(jù)的內(nèi)存區(qū)域月褥。
EXE文件中不存在堆和棧弛随,堆和棧是向內(nèi)存申請的空間。
因此吓坚,內(nèi)存中的文件的構(gòu)成為:用于變量的內(nèi)存空間+用于函數(shù)的內(nèi)存空間+用于堆的內(nèi)存空間+用于棧的內(nèi)存空間撵幽。
內(nèi)存泄漏
棧:對數(shù)據(jù)進(jìn)行存儲和清理的代碼,由編譯器自動生成礁击。
堆:對堆的空間的申請分配和釋放,由程序員自己編寫代碼實現(xiàn)逗载。C語言中哆窿,申請分配:malloc()函數(shù),釋放:free()函數(shù)厉斟;C++語言中挚躯,申請分配:new運算符,釋放:delete運算符擦秽。
如果沒有明確釋放申請分配的內(nèi)存码荔,就可能造成內(nèi)存泄漏(memory leak)漩勤。