編譯原理編譯系統(tǒng)和運(yùn)行系統(tǒng)學(xué)習(xí)培訓(xùn)模板課件_第1頁(yè)
編譯原理編譯系統(tǒng)和運(yùn)行系統(tǒng)學(xué)習(xí)培訓(xùn)模板課件_第2頁(yè)
編譯原理編譯系統(tǒng)和運(yùn)行系統(tǒng)學(xué)習(xí)培訓(xùn)模板課件_第3頁(yè)
編譯原理編譯系統(tǒng)和運(yùn)行系統(tǒng)學(xué)習(xí)培訓(xùn)模板課件_第4頁(yè)
編譯原理編譯系統(tǒng)和運(yùn)行系統(tǒng)學(xué)習(xí)培訓(xùn)模板課件_第5頁(yè)
已閱讀5頁(yè),還剩60頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、第十一章 編譯系統(tǒng)和運(yùn)行系統(tǒng) 本章內(nèi)容C語(yǔ)言編譯系統(tǒng)預(yù)處理器、匯編器、連接器目標(biāo)文件的格式、靜態(tài)庫(kù)、動(dòng)態(tài)連接Java運(yùn)行系統(tǒng)無用單元收集(垃圾收集)掌握從源程序到可執(zhí)行目標(biāo)程序的實(shí)際處理過程對(duì)實(shí)際參與軟件開發(fā)是直接有用的11.1 C語(yǔ)言編譯系統(tǒng)預(yù)處理器源程序修改后的源程序可重定位的目標(biāo)程序可重定位的目標(biāo)文件庫(kù)編譯器匯編器匯編程序連接器可執(zhí)行的目標(biāo)程序 C源程序可以分成若干個(gè)模塊 分別進(jìn)行預(yù)處理、編譯和匯編、形成可重定位的目標(biāo)文件 目標(biāo)文件和必要的庫(kù)文件連接成一個(gè)可執(zhí)行的目標(biāo)文件 gcc和cc是編譯驅(qū)動(dòng)程序的名字 11.1 C語(yǔ)言編譯系統(tǒng)main.c(1) #if 1(2) int buf2;

2、(3) #else(4) int buf2 = 10,20;(5) #endif(6) void swap();(7) #define A buf0 (8) int main()(9) (10)scanf(%d, %d, buf, buf+1);(11)swap();(12)printf(%d, %d,A, buf1);(13)return 0;(14) swap.c(1) extern int buf2;(2) int *bufp0 = buf;(3) int *bufp1;(4) void swap()(5) (6) int temp;(7)bufp1 = buf+1;(8)temp =

3、*bufp0;(9)*bufp0 = *bufp1;(10)*bufp1 = temp;(11) 11.1 C語(yǔ)言編譯系統(tǒng)11.1.1 預(yù)處理器gcc首先調(diào)用預(yù)處理器cpp,將源程序文件翻譯成一個(gè)ASCII中間文件,它是經(jīng)修改后的源程序cpp實(shí)現(xiàn)以下功能文件包含宏展開條件編譯11.1 C語(yǔ)言編譯系統(tǒng)main.c(1) #if 1(2) int buf2; (3) #else(4) int buf2 = 10,20;(5) #endif(6) void swap();(7) #define A buf0 (8) int main()(9) (10)scanf(%d, %d, buf, buf+1

4、);(11)swap();(12)printf(%d, %d,A, buf1);(13)return 0;(14) main.i(1) # 1 “main.c”(2) (3) int buf2;(4) (5) (6) (7) void swap(); (8)(9) int main()(10) (11) scanf(%d, %d, buf, buf+1);(12) swap();(13) printf(%d,%d,buf0, );(14) return 0;(15) 11.1 C語(yǔ)言編譯系統(tǒng)11.1.2 匯編器GCC系統(tǒng)的編譯器cc1產(chǎn)生匯編代碼最簡(jiǎn)單的匯編器對(duì)輸入進(jìn)行兩遍掃描一遍掃描完成匯編

5、代碼到可重定位目標(biāo)代碼的翻譯也是完全可能的用gcc S main.c可以得到匯編文件main.s用as o main.o main.s可以將main.s匯編成可重定位目標(biāo)文件main.o 11.1 C語(yǔ)言編譯系統(tǒng)一段匯編代碼.L2:cmpl $0,-4(%ebp)jne .L6jmp .L11.L11:cmpl $0,-8(%ebp)jne .L6jmp .L12.L12:jmp .L5.p2align 4,7.L6:11.1 C語(yǔ)言編譯系統(tǒng)11.1.3 連接器目標(biāo)模塊或目標(biāo)文件的形式可重定位的目標(biāo)文件可執(zhí)行的目標(biāo)文件共享目標(biāo)文件 一種特殊的可重定位目標(biāo)文件 在裝入程序或運(yùn)行程序時(shí),動(dòng)態(tài)地裝入

6、到內(nèi)存并連接11.1 C語(yǔ)言編譯系統(tǒng)連接是一個(gè)收集、組織程序所需的不同代碼和數(shù)據(jù)的過程,以便程序能被裝入內(nèi)存并被執(zhí)行連接的時(shí)機(jī)編譯時(shí)裝入時(shí)運(yùn)行時(shí)靜態(tài)連接器動(dòng)態(tài)連接器11.1 C語(yǔ)言編譯系統(tǒng)一個(gè)重定位模塊M可能定義和引用的符號(hào)全局符號(hào) 指那些在模塊M中定義,可以被其它模塊引用的符號(hào)局部符號(hào) 指那些在模塊M中定義,且只能在本模塊中引用的符號(hào)外部符號(hào) 指那些由模塊M引用并由其它模塊定義符號(hào)符號(hào)解析識(shí)別各個(gè)目標(biāo)模塊中定義和引用的符號(hào),為每一個(gè)符號(hào)引用確定它所關(guān)聯(lián)的一個(gè)同名符號(hào)的定義重定位11.1 C語(yǔ)言編譯系統(tǒng)11.1.4 目標(biāo)文件的格式目標(biāo)文件格式隨系統(tǒng)不同而不同介紹Unix的ELF(Executa

7、ble and Linkable Format)格式Linux、System V Unix的后期版本、BSD Unix變體和Sun Solaris,都使用Unix的ELF格式11.1 C語(yǔ)言編譯系統(tǒng)ELF頭描述了字的大小產(chǎn)生此文件的系統(tǒng)的字節(jié)次序目標(biāo)文件的類型機(jī)器類型節(jié)頭表的位置、條目多少其它ELF頭.text.rodata.data.bss.symtab.rel.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng)節(jié)頭表描述目標(biāo)文件中各節(jié)的位置和大小處于目標(biāo)文件的末尾ELF頭.text.rodata.data.bss.symtab.

8、rel.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng).text節(jié) 被編譯程序的機(jī)器代碼.rodata節(jié) 諸如printf語(yǔ)句中的格式串和switch語(yǔ)句的跳轉(zhuǎn)表等只讀數(shù)據(jù).data節(jié) 已初始化的全局變量 ELF頭.text.rodata.data.bss.symtab.rel.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng).bss節(jié)(.comm 節(jié)) 未初始化的全局變量 在目標(biāo)文件中不占實(shí)際的空間.symtab節(jié)記錄在該模塊中定義和引用的函數(shù)和全局變量的信息的符

9、號(hào)表ELF頭.text.rodata.data.bss.symtab.rel.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng).symtab節(jié)TypeFUNCOBJECTBindGLOBALLOCALEXTERNELF頭.text.rodata.data.bss.symtab.rel.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng).symtab節(jié)NameValue偏移地址,或絕對(duì)地址Size字節(jié)數(shù)ELF頭.text.rodata.data.bss.symtab.re

10、l.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng).rel.text節(jié) .text節(jié)中需要修改的單元的位置列表.rel.data節(jié)用于被本模塊引用或定義的全局變量的重定位信息ELF頭.text.rodata.data.bss.symtab.rel.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng).debug節(jié)用于調(diào)試程序的調(diào)試符號(hào)表.line節(jié)源文件和.text節(jié)中的機(jī)器指令之間的行號(hào)映射 .strtab一組有空結(jié)束符的串構(gòu)成的串表ELF頭.text.rodata.

11、data.bss.symtab.rel.text.rel.data.debug.line.strtab節(jié)頭表0描述目標(biāo)文件的節(jié)節(jié)11.1 C語(yǔ)言編譯系統(tǒng)11.1.5 符號(hào)解析將每個(gè)符號(hào)引用正確地與某可重定位模塊的符號(hào)表中的一個(gè)符號(hào)定義相關(guān)聯(lián),從而確定各個(gè)符號(hào)引用的位置在所有輸入模塊中都找不到被引用符號(hào)的定義,則打印錯(cuò)誤消息并結(jié)束連接需要定義解析規(guī)則11.1 C語(yǔ)言編譯系統(tǒng)解析規(guī)則函數(shù)和已初始化的全局變量稱為強(qiáng)符號(hào);未初始化的全局變量稱為弱符號(hào)不允許有多重的強(qiáng)符號(hào)定義出現(xiàn)一個(gè)強(qiáng)符號(hào)定義和多個(gè)弱符號(hào)定義時(shí),選擇強(qiáng)符號(hào)的定義出現(xiàn)多個(gè)弱符號(hào)定義時(shí),選擇任意一個(gè)弱符號(hào)的定義 11.1 C語(yǔ)言編譯系統(tǒng)11

12、.1.6 靜態(tài)庫(kù)將相關(guān)的可重定位目標(biāo)模塊打包成一個(gè)文件,作為連接器的輸入連接器僅復(fù)制庫(kù)中被應(yīng)用程序引用的模塊gcc c swap.c編譯ar rcs mylib.a swap.o建庫(kù)gcc static o swap1 main.c /usr/lib/libc.a mylib.a 生成可執(zhí)行文件11.1 C語(yǔ)言編譯系統(tǒng)printf.o等可重定位文件翻譯器main.c源文件連接器main.omylib.aswap.olibc.a 靜態(tài)庫(kù)swap1完全連接的可執(zhí)行文件和靜態(tài)庫(kù)連接 11.1 C語(yǔ)言編譯系統(tǒng)11.1.7 可執(zhí)行目標(biāo)文件及裝入可執(zhí)行目標(biāo)文件與可重定位目標(biāo)文件格式類似可執(zhí)行目標(biāo)文件的裝入

13、由加載器完成11.1 C語(yǔ)言編譯系統(tǒng)讀/寫內(nèi)存段ELF頭段頭表.init.text.rodata.data.bss.symtab.debug.line.strtab節(jié)頭表只讀內(nèi)存段符號(hào)表和調(diào)試信息,不裝入內(nèi)存描述目標(biāo)文件的節(jié)將下面的節(jié)映射到運(yùn)行時(shí)的內(nèi)存段典型的ELF可執(zhí)行目標(biāo)文件11.1 C語(yǔ)言編譯系統(tǒng)Linux運(yùn)行時(shí)的內(nèi)存映像內(nèi)核用戶棧(運(yùn)行時(shí)創(chuàng)建)共享庫(kù)的內(nèi)存區(qū)域運(yùn)行時(shí)的堆(運(yùn)行時(shí)用malloc創(chuàng)建)讀/寫段(.data, .bss)只讀段(.init, .text, .rodata)未使用0 xc00000000 x400000000 x08048000對(duì)用戶代碼不可見 %esp(棧指針

14、)brk從可執(zhí)行文件裝入011.1 C語(yǔ)言編譯系統(tǒng)這里描述的裝入過程從概念上來說是正確的若需要了解裝入過程真正是怎樣工作的,必須在理解了進(jìn)程、虛擬內(nèi)存和內(nèi)存分頁(yè)等概念以后11.1 C語(yǔ)言編譯系統(tǒng)11.1.8 動(dòng)態(tài)連接靜態(tài)庫(kù) 周期性地被維護(hù)和更新 內(nèi)存可能有多份printf和scanf的代碼共享庫(kù) 在運(yùn)行時(shí)可以裝到任意的內(nèi)存位置,被內(nèi)存中的進(jìn)程共享11.1 C語(yǔ)言編譯系統(tǒng)共享庫(kù)以兩種不同的方式被共享共享庫(kù)的代碼和數(shù)據(jù)被所有引用該庫(kù)的可執(zhí)行目標(biāo)文件所共享共享庫(kù)的.text節(jié)在內(nèi)存中的一個(gè)副本可以被正在運(yùn)行的不同進(jìn)程共享11.1 C語(yǔ)言編譯系統(tǒng)可重定位文件翻譯器(cpp,cc1,as)main.c源

15、文件連接器(ld)main.olibc.somylib.so重定位和符號(hào)表信息部分連接的可執(zhí)行目標(biāo)文件swap2加載器(execve)libc.somylib.so動(dòng)態(tài)連接器(ld-linux.so)代碼和數(shù)據(jù)此時(shí),動(dòng)態(tài)連接器是內(nèi)存中已完全連接的可執(zhí)行代碼11.1 C語(yǔ)言編譯系統(tǒng)加載器通常裝入和運(yùn)行動(dòng)態(tài)連接器動(dòng)態(tài)連接器接著完成連接任務(wù)把libc.so的文本和數(shù)據(jù)裝入內(nèi)存并進(jìn)行重定位把mylib.so的文本和數(shù)據(jù)裝入內(nèi)存并進(jìn)行重定位重定位swap2中任何對(duì)libc.so或mylib.so定義的符號(hào)的引用將控制傳遞給應(yīng)用程序11.1 C語(yǔ)言編譯系統(tǒng)11.1.9 處理目標(biāo)文件的一些工具ar創(chuàng)建靜態(tài)庫(kù)

16、,插入、刪除、羅列和提取成strings 列出包含在目標(biāo)文件中的所有可打印串strip 從一個(gè)目標(biāo)文件中刪除符號(hào)表信息nm 列出一個(gè)目標(biāo)文件的符號(hào)表中定義的符號(hào)size 列出目標(biāo)文件中各段的名字和大小readelf 顯示目標(biāo)文件的完整結(jié)構(gòu),包括編碼在ELF頭中的所有信息。它包括了size和nm的功能objdump可以顯示目標(biāo)文件中的所有信息。其最有用的功能是反匯編.text節(jié)中的二進(jìn)制指令ldd列出可執(zhí)行目標(biāo)文件在運(yùn)行時(shí)需要的共享庫(kù) 11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)Java語(yǔ)言簡(jiǎn)單性、分布性、安全性、可移植性等我們關(guān)心的是:平臺(tái)無關(guān)性Java虛擬機(jī)技術(shù)是實(shí)現(xiàn)Java平臺(tái)無關(guān)性特點(diǎn)的關(guān)鍵Java

17、運(yùn)行系統(tǒng)就是Java虛擬機(jī)的一個(gè)實(shí)現(xiàn)11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)11.2.1 Java虛擬機(jī)語(yǔ)言簡(jiǎn)介Java程序首先由Java編譯器把它編譯成字節(jié)碼,也就是JVML程序常量池: 各種字符串常量,類似于傳統(tǒng)程序設(shè)計(jì)語(yǔ)言中的符號(hào)表類成員信息: 域信息表和方法信息表JVML指令序列11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)Java源程序中的方法int calculate (int i)int j =2;return (i+j) (j-1); 對(duì)應(yīng)的字節(jié)碼程序:int calculate (int i)iconst_2istore_2iload_1iload_2iaddiload_2iconst_1isub

18、imulireturn11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)11.2.2 Java虛擬機(jī)Java虛擬機(jī)一般由以下幾個(gè)部分構(gòu)成:類加載器(字節(jié)碼驗(yàn)證器)解釋器或/和編譯器包括無用單元收集器和線程控制模塊在內(nèi)的運(yùn)行支持系統(tǒng),另外還有一些標(biāo)準(zhǔn)類和應(yīng)用接口的class文件庫(kù)Java源程序Java字節(jié)碼Java編譯器Java字節(jié)碼在網(wǎng)絡(luò)上移動(dòng)Java虛擬機(jī)類加載器(字節(jié)碼驗(yàn)證)Java類庫(kù)字節(jié)碼解釋器即時(shí)編譯器無用單元收集器線程/同步機(jī)制運(yùn)行時(shí)支持LinuxWin32/NT硬件設(shè)備Solaris11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)C語(yǔ)言數(shù)據(jù)棧用來存放生存期和過程一次活動(dòng)的生存期一致的局部變量數(shù)據(jù)堆用來存放生存期和

19、過程一次活動(dòng)的生存期不一定一致的動(dòng)態(tài)變量 程序員通過malloc和free函數(shù)參與堆的管理 不安全的一個(gè)根源(懸空指針、內(nèi)存泄漏)Java語(yǔ)言數(shù)據(jù)棧除對(duì)象和數(shù)組外,都分配在棧上數(shù)據(jù)堆對(duì)象和數(shù)組分配在堆上 出于安全的要求,程序員不參與堆管理11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)無用單元收集(俗稱垃圾收集)無用單元(理論上)那些在繼續(xù)運(yùn)行過程中不會(huì)再使用的數(shù)據(jù)單元收集器采用穩(wěn)妥策略實(shí)際上并非總能判斷出一個(gè)數(shù)據(jù)記錄的值以后是否還需要通過根集(roots set,在棧上)以及從根集開始的可達(dá)性來定義變量的活躍性無用單元(實(shí)現(xiàn)上)通常指那些不可能從程序變量經(jīng)指針鏈到達(dá)的堆分配記錄11.2 Java語(yǔ)言的運(yùn)行系

20、統(tǒng)11.2.3 即時(shí)編譯器當(dāng)一個(gè)類的某個(gè)方法第一次被調(diào)用時(shí),虛擬機(jī)才激活即時(shí)編譯器將它編譯成機(jī)器代碼生成的代碼的執(zhí)行速度可以達(dá)到解釋執(zhí)行的10倍但是執(zhí)行過程不得不等待編譯的結(jié)束,因此使得執(zhí)行時(shí)間變長(zhǎng)很多虛擬機(jī)都會(huì)使用快速解釋器和優(yōu)化編譯器的組合或者是簡(jiǎn)單編譯器和復(fù)雜編譯器的組合11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)即時(shí)編譯對(duì)象引用方法表指針實(shí)例數(shù)據(jù)方法表類指針方法0代碼指針方法1代碼指針compile-me代碼段編譯得到的機(jī)器代碼(本地代碼)即時(shí)編譯器 11.2 Java語(yǔ)言的運(yùn)行系統(tǒng)重編譯機(jī)制字節(jié)碼未優(yōu)化機(jī)器代碼優(yōu)化機(jī)器代碼快速代碼生成的編譯器優(yōu)化編譯器計(jì)數(shù)器統(tǒng)計(jì)數(shù)據(jù)11.3 無用單元收集 無用單

21、元收集器需要根據(jù)數(shù)據(jù)的活躍性來判斷哪些是無用單元活躍性分析采用穩(wěn)妥策略,是通過根集以及從根集開始的可達(dá)性來定義活躍性因此從實(shí)現(xiàn)的角度,無用單元是那些不可能從程序變量經(jīng)指針鏈到達(dá)的堆分配記錄 無用單元收集可能需要來自編譯器、操作系統(tǒng)和硬件方面的支持本節(jié)簡(jiǎn)要介紹一些主要的無用單元收集方法,并且描述編譯器和收集器之間的一些相互影響11.3 無用單元收集 11.3.1 標(biāo)記和清掃方法概述:首先標(biāo)記堆上所有可達(dá)記錄,然后回收未被標(biāo)記的記錄 根集包含了全局變量、活動(dòng)記錄棧中的局部變量和被活躍著的過程使用的寄存器堆上活躍記錄的集合是從根集開始的任何一條指針路徑上的記錄的集合任何圖遍歷算法,都可用于標(biāo)記所有的

22、可達(dá)記錄清掃從堆的首地址開始, 逐個(gè)記錄地考察整個(gè)堆, 尋找未被標(biāo)記的記錄, 把它們鏈成一個(gè)空閑鏈表 11.3 無用單元收集 11.3.1 標(biāo)記和清掃傳統(tǒng)的標(biāo)記和清掃方法的問題 碎片問題:當(dāng)要分配一個(gè)n字節(jié)大小的記錄時(shí),發(fā)現(xiàn)有很多小于n字節(jié)的空閑塊存在,但就是沒有合適的空閑塊可分配給這個(gè)記錄引用局部性問題:使用塊和空閑塊相互交織,使得當(dāng)前要使用的各個(gè)活躍記錄被分散到很多的虛擬內(nèi)存頁(yè)中,這些頁(yè)在內(nèi)存中可能被頻繁地?fù)Q進(jìn)換出 11.3 無用單元收集 11.3.2 引用計(jì)數(shù)方法概述:通過記住有多少指針指向每個(gè)記錄來直接完成標(biāo)記,引用計(jì)數(shù)存在各記錄中編譯器需要在每個(gè)出現(xiàn)指針存儲(chǔ)的地方生成額外的指令,以調(diào)

23、整一些引用計(jì)數(shù)器的值當(dāng)一個(gè)記錄的引用計(jì)數(shù)值為0的時(shí)候,就可以把該記錄加入空閑鏈表被回收記錄本身的指針域都要一一檢查,它們所指向的記錄的引用計(jì)數(shù)值也都要減1 11.3 無用單元收集 11.3.2 引用計(jì)數(shù)引用計(jì)數(shù)方法的問題碎片和引用局部性問題仍然存在并非總有效:對(duì)于循環(huán)的數(shù)據(jù)結(jié)構(gòu)會(huì)失效,因?yàn)檫@些記錄的引用計(jì)數(shù)也永遠(yuǎn)不可能減到零代價(jià)高,因?yàn)槊慨?dāng)執(zhí)行指針存儲(chǔ)的時(shí)候,都需要執(zhí)行額外的指令來調(diào)整一些引用計(jì)數(shù)引用計(jì)數(shù)收集已經(jīng)被跟蹤型收集代替,標(biāo)記和清掃收集方法就是一種跟蹤型收集方法11.3 無用單元收集 11.3.3 拷貝收集方法概述這個(gè)算法和標(biāo)記和清除算法一樣,也遍歷可達(dá)記錄所組成的有向圖,只不過它在遍

24、歷的同時(shí)進(jìn)行清掃,并且這種清掃主要是拷貝活躍記錄這種方法將堆空間分成大小相等的兩塊,每塊都是連續(xù)的區(qū)域11.3 無用單元收集 to_spacefrom_spacefrom_spacerootsfreelimit(a) 收集前(b)收集后rootsto_spacefreelimit11.3 無用單元收集 11.3.3 拷貝收集優(yōu)缺點(diǎn)從理論上來說,只要有足夠的內(nèi)存,可得到很高的效率可以將活躍數(shù)據(jù)緊縮在一起,碎片情況消失,引用局部性得到改善需要的空間是實(shí)際需要空間的兩倍拷貝大記錄的代價(jià)太大11.3 無用單元收集 11.3.4 分代收集原理很多程序在運(yùn)行過程中,新建記錄很可能很快死去,不會(huì)出現(xiàn)對(duì)它的拷

25、貝;反過來,一個(gè)記錄在幾次收集后還可到達(dá)的話,那么很可能還會(huì)活躍到許多次收集后收集器應(yīng)該將精力集中到“年輕”的數(shù)據(jù)上,因?yàn)檫@里有相對(duì)高的無用單元比率 11.3 無用單元收集 11.3.4 分代收集基本做法堆被分成代,最年輕的記錄在G0代,Gi (i 0)代中的記錄比Gi1代中的任何記錄都要老。越年輕的代越被頻繁地收集對(duì)G0代進(jìn)行收集時(shí),這時(shí)的根集不僅僅是程序變量,它還包括G1, G2,中指向G0的指針。幸好,老記錄指向年輕得多的記錄的情況極少出現(xiàn),通常是較新的記錄指向老記錄為了避免確定G0的根集時(shí)在G1, G2,中查找,需要編譯器提供一些支持,方法有多種11.3 無用單元收集 11.3.5 漸

26、增式收集緣由雖然收集時(shí)間的總和只占整個(gè)程序運(yùn)行時(shí)間很小的百分比,但是收集器仍然有可能偶爾將運(yùn)行程序中斷相對(duì)長(zhǎng)的時(shí)間,對(duì)于交互式程序和實(shí)時(shí)程序來說,這一點(diǎn)是難以接受的改進(jìn)漸增式收集:程序運(yùn)行和無用單元收集交錯(cuò)進(jìn)行困難在于,當(dāng)收集器在做遍歷以得到一個(gè)可達(dá)記錄圖時(shí),運(yùn)行程序并沒有停止修改可達(dá)記錄圖 11.3 無用單元收集 11.3.6 編譯器與收集器之間的相互影響對(duì)收集器的底層有下面這些基本要求 能確定堆上分配的記錄大小能定位包含在堆記錄里的指針能定位所有在全局變量中的指針能在程序中任何可進(jìn)行收集的地方找到所有在活動(dòng)記錄棧中和寄存器中的指針能找到所有由指針運(yùn)算所產(chǎn)生的值指向的記錄能在記錄被移動(dòng)時(shí),更

27、新所有涉及到的指針值很多所需信息只有在編譯時(shí)能夠獲得例 題 1如果cfile是一個(gè)C語(yǔ)言源程序(注意,該文件名沒有后綴),在X86/Linux機(jī)器上,命令cc cfile的結(jié)果是錯(cuò)誤信息/usr/bin/ld: cfile: file format not recognized: treating as linker script/usr/bin/ld: cfile: 1: parse errorcollect2: ld returned 1 exit status請(qǐng)解釋為什么會(huì)是這樣的錯(cuò)誤信息例 題 2下面是C語(yǔ)言的一個(gè)程序:long gcd(p,q) long p,q; if (p%q =

28、 0) return q; else return gcd(q, p%q);main() printf(n%ldn,gcdx(4,12);在X86/Linux機(jī)器上,用gcc命令得到的編譯結(jié)果如下In function main:undefined reference to gcdxld returned 1 exit status.請(qǐng)問,這個(gè)gcdx沒有定義,是在編譯時(shí)發(fā)現(xiàn)的,還是在連接時(shí)發(fā)現(xiàn)的?試說明理由例 題 3一些C程序設(shè)計(jì)的教材上指出“在需要使用標(biāo)準(zhǔn)I/O庫(kù)中的函數(shù)時(shí),應(yīng)在程序前使用#include 預(yù)編譯命令,但在用printf和scanf函數(shù)時(shí),則可以不要?!?但事實(shí)上并非僅限于這兩個(gè)函數(shù)。例如下面的C程序編譯后運(yùn)行時(shí)輸出字符A并換行,它并沒有預(yù)編譯命令#include 。試解釋為什么main()putchar(A);putchar(n);例 題 4C的一個(gè)源文件可以包含若干個(gè)函數(shù),該源文件經(jīng)編譯可以生成一個(gè)目標(biāo)文件;若干個(gè)目標(biāo)文件可以構(gòu)成一個(gè)函數(shù)庫(kù)。如果一個(gè)用戶程序引用庫(kù)中的某個(gè)函數(shù),那么,在連接時(shí)的做法是下面三種情況的哪一種,說明你的理由將該庫(kù)函數(shù)的目標(biāo)代碼連到用戶程序?qū)⒃搸?kù)函數(shù)的目標(biāo)代碼所在的目標(biāo)文件連到用戶程序?qū)⒃摵瘮?shù)庫(kù)全部連到用戶程序例 題 5cc是UNIX

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論