




版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
1、客戶(hù)端做到一定程度,都會(huì)做啟動(dòng)優(yōu)化,啟動(dòng)優(yōu)化主要有如下方式1、 dll 基址固定2、 dll 延遲加載3、 dll 文件預(yù)讀4、 程序二進(jìn)制文件連續(xù)分布5、 二進(jìn)制文件relink6、 啟動(dòng)邏輯優(yōu)化調(diào)整客戶(hù)端性啟動(dòng)性能優(yōu)化比起服務(wù)器要簡(jiǎn)單,服務(wù)器動(dòng)不動(dòng)就搞緩存、分布式、算法調(diào)優(yōu)、客戶(hù)端啟動(dòng)優(yōu)化說(shuō)來(lái)說(shuō)去,核心思想不過(guò)下幾點(diǎn)1、 減少文件io2、 減少page fault 3、 減少磁盤(pán)跨磁道操作4、 啟動(dòng)邏輯前移,先顯示ui,后加載邏輯涉及到的工具1、 process monitor 查看啟動(dòng)的時(shí)候file io2、 xpref 分析啟動(dòng)的時(shí)候性能,消耗時(shí)間的部分在哪塊3、 wcontig 查看
2、文件碎片的小工具4、 sawbuck, 這是google 提供的一系列二進(jìn)制重組工具。用了這些方法和工具后,完全可以忽略掉微軟的prefetcher,這個(gè)工具1不開(kāi)源,其次資料非常少,能起到的作用也有限,微軟只會(huì)用閉源這一招,但是比他強(qiáng)大的方法實(shí)在太多。重點(diǎn)講下 基址固定,dll文件預(yù)讀,二進(jìn)制relink,二進(jìn)制文件磁盤(pán)整理基址固定: 每個(gè)DLL和可執(zhí)行文件都有一個(gè)首選基地址。它表示該模塊被映射到進(jìn)程地址空間時(shí)最佳的內(nèi)存地址。在構(gòu)建可執(zhí)行文件時(shí),默認(rèn)情況下鏈接器會(huì)將它的首選基地址設(shè)為0x400000。對(duì)于DLL來(lái)說(shuō),鏈接器會(huì)將它的首選基地址設(shè)為0x1000
3、0000,然后將該地址以及代碼、數(shù)據(jù)的相關(guān)地址都寫(xiě)入它們的PE文件中。當(dāng)它們被加載時(shí),加載程序讀取首選基地址的值,并試圖把它們加載到相應(yīng)位置。 對(duì)于可執(zhí)行文件和DLL中的代碼,它們運(yùn)行的時(shí)候所引用的的數(shù)據(jù)的地址,在鏈接的時(shí)候就已經(jīng)確定。并且這些都是當(dāng)exe文件或是DLL被加載到它們的首選基地址處時(shí)才是有效的。 對(duì)于匯編代碼:MOV 0x00414540 ,5 它是將5賦值給0x00414
4、540處的內(nèi)存地址。此地址已經(jīng)固定。它說(shuō)明當(dāng)EXE或是DLL被加載到0x400000處時(shí),0x00414540才是正確的。然而并不是所有模塊都會(huì)被載入到首選基地址處。一旦模塊沒(méi)有被加載到首選基地址處,在該模塊中對(duì)于地址的引用都是錯(cuò)誤的,這時(shí)候基址重定位就是必須的。所謂重定位就是當(dāng)某模塊未被載入到首選基地址時(shí),加載器會(huì)計(jì)算模塊實(shí)際載入的地址跟首選基地址的差值,將這個(gè)差值加到機(jī)器指令所引用的原來(lái)的地址,得到的就是模塊中各指令所引用的數(shù)據(jù)在本進(jìn)程地址空間的正確地址,隨后加載器會(huì)修正模塊中對(duì)每個(gè)內(nèi)存地址的引用。 為了便
5、于系統(tǒng)有能力對(duì)各數(shù)據(jù)的地址進(jìn)行修正,windows提供了重定位段。它包含很多基址重定位信息。這個(gè)段是有很多項(xiàng)組成。每一項(xiàng)表示一個(gè)要重定位的地址,它包含一個(gè)字節(jié)偏移量列。該偏移量表示一條機(jī)器指令所使用的內(nèi)存地址。這便于系統(tǒng)在確認(rèn)該模塊需要重定位時(shí)對(duì)需要重定位的數(shù)據(jù)進(jìn)行定位。 當(dāng)鏈接器在構(gòu)建模塊時(shí),它會(huì)將重定位段嵌入到生成的文件中。 對(duì)exe文件來(lái)說(shuō),由于每個(gè)文件總是使用獨(dú)立的地址空間,所以exe文件總是可以被加載到首選基地址上。對(duì)于DLL來(lái)說(shuō)
6、,很多DLL都是使用寄主進(jìn)程的地址空間,不能保證各DLL的首選基地址各不相同。所以DLL一定要有重定位段,除非在鏈接時(shí)使用/FIXED 開(kāi)關(guān)。此時(shí)鏈接器會(huì)去掉重定位段。如果此后模塊未被載入首選基地址,由于無(wú)法重定位,模塊不會(huì)被載入,導(dǎo)致程序無(wú)法運(yùn)行。 如果加載程序?qū)⒛K加載到它的首選基地址,那么系統(tǒng)就不會(huì)訪(fǎng)問(wèn)模塊的重定位段。否則系統(tǒng)會(huì)打開(kāi)模塊的重定位段并遍歷其中的條目,對(duì)每個(gè)條目,加載程序先找到包含機(jī)器指令的那個(gè)存儲(chǔ)頁(yè)面,算出差值,將差值加到機(jī)器指令當(dāng)前正在使用的內(nèi)存地址上。 &
7、#160; 對(duì)于上例:假如它是在一DLL中。如果該DLL實(shí)際被加載到0x20000000處,由于首選基地址是0x10000000,兩者差為0x10000000。加載器修正之后,該指令所引用的實(shí)際地址變成了0x10414540。這樣對(duì)各個(gè)數(shù)據(jù)的引用都會(huì)引用到正確的地址 。 要知道基址重定位需要很大的系統(tǒng)開(kāi)銷(xiāo): 1:加載程序需要遍歷模塊重定位段并修改模塊中大量的代碼。這增加了程序初始化時(shí)間。
8、0; 2:當(dāng)加載程序?qū)懭肽K的代碼頁(yè)面時(shí),由于它們具有寫(xiě)時(shí)復(fù)制屬性,寫(xiě)時(shí)復(fù)制機(jī)制會(huì)導(dǎo)致系統(tǒng)從頁(yè)交換文件中分配空間來(lái)容納這些修改后的頁(yè)面。 明白了這些我們應(yīng)該清楚,為每個(gè)映射到進(jìn)程的DLL設(shè)置不同的首選基地址是必須的。在鏈接時(shí),選中ProjectPropertiesLinkerAdvancved,然后在BaseAddress中設(shè)置。這聽(tīng)起來(lái)很容易,但是如果程序需要載入大量的模塊,我們還需要這樣一個(gè)一個(gè)設(shè)置嗎?話(huà)又說(shuō)回來(lái)了,有些模塊并不是我們創(chuàng)建的,我們應(yīng)該怎么辦呢? &
9、#160; Windows為我們提供了一個(gè)名為:Rebase.exe的工具。 如果在執(zhí)行它時(shí)為它提供一組映像文件名,它會(huì)執(zhí)行以下操作: 1:它會(huì)模擬創(chuàng)建一個(gè)地址空間。 2:它會(huì)打開(kāi)這一組映像文件,并得到它們的大小和首選基地址。 3:它會(huì)在模擬的地址空間對(duì)模塊重定位的過(guò)程進(jìn)行模擬,以便各模塊沒(méi)有交叉。 4:對(duì)于每個(gè)需要重定位的模塊,它會(huì)解析模塊的重定位段,并修
10、改模塊在磁盤(pán)文件中的代碼。 5:將每個(gè)模塊新的首選基地址寫(xiě)入各個(gè)模塊磁盤(pán)文件中。 所以推薦你在構(gòu)建完所有項(xiàng)目后運(yùn)行Rebase.exe。 由于Microsoft在發(fā)布windows之前,已經(jīng)使用Rebase.exe對(duì)所有操作系統(tǒng)提供的模塊進(jìn)行了重定位,所以即使將操作系統(tǒng)的所有模塊都映射到進(jìn)程地址空間也不會(huì)發(fā)生交叉的現(xiàn)象。我們不再需要對(duì)隨操作系統(tǒng)一起發(fā)布的模塊進(jìn)行基址重定位。 使用R
11、ebase.exe或是手工修改各模塊的首選基地址,以免某些模塊不被加載到首選基地址上。這當(dāng)然可以提高系統(tǒng)性能。但是我們還可以更顯著的提高性能。 這種技術(shù)就是模塊綁定。 讓我們來(lái)回顧一下程序加載模塊的過(guò)程: 加載程序首先為進(jìn)程創(chuàng)建虛擬地址空間,接著把可執(zhí)行文件映射進(jìn)來(lái)。之后打開(kāi)可執(zhí)行文件的導(dǎo)入段,將該程序需要的DLL進(jìn)行定位并把它們也載入進(jìn)來(lái)。隨著加載程序?qū)LL模塊加載到進(jìn)程地址空間,它會(huì)同時(shí)檢查每個(gè)DL
12、L的導(dǎo)入段。如果一個(gè)DLL有導(dǎo)入段,那么加載程序會(huì)繼續(xù)將所需的額外的DLL模塊映射到進(jìn)程地址空間。當(dāng)所有DLL都已被載入進(jìn)程地址空間,它開(kāi)始修復(fù)所有對(duì)導(dǎo)入符號(hào)的引用。這時(shí)它會(huì)再次查看每個(gè)模塊的導(dǎo)入段,對(duì)導(dǎo)入段中每個(gè)符號(hào),它會(huì)檢查對(duì)應(yīng)DLL的導(dǎo)出段,然后取出該符號(hào)的RVA并給他加上DLL模塊被載入到進(jìn)程地址空間的虛擬地址。計(jì)算出符號(hào)在進(jìn)程的虛擬地址(VA),寫(xiě)入到可執(zhí)行模塊的導(dǎo)入段中。這樣當(dāng)一個(gè)符號(hào)被引用的時(shí)候,程序會(huì)查看可執(zhí)行模塊的導(dǎo)入段并取得導(dǎo)入符號(hào)虛擬地址(VA)。 這就是模塊加載的大概過(guò)程。可以看到,每次
13、在程序加載時(shí),都要將導(dǎo)入段的符號(hào)地址從其他DLL中獲得,然后寫(xiě)入到導(dǎo)入段的相應(yīng)位置(IAT)。這十分耗費(fèi)時(shí)間。 所謂的模塊綁定就是說(shuō)在運(yùn)行之前,所有導(dǎo)入符號(hào)在進(jìn)程地址空間的地址已經(jīng)獲得,不需要加載時(shí)在計(jì)算出來(lái)這節(jié)省初始化時(shí)間,另外將導(dǎo)入符號(hào)的虛擬地址寫(xiě)入exe模塊的導(dǎo)入段,也會(huì)由于寫(xiě)時(shí)復(fù)制機(jī)制將要修改的頁(yè)面以系統(tǒng)頁(yè)交換文件為后備存儲(chǔ)器。這會(huì)遇到與基址重定位相似的問(wèn)題。所以模塊綁定對(duì)提高系統(tǒng)性能的提高是顯著的。 VisualStudio提供了一個(gè)名為Bin
14、d.exe的工具,如果在執(zhí)行它的時(shí)候傳給它一個(gè)映像文件名,它會(huì)對(duì)其執(zhí)行模塊綁定操作。 具體過(guò)程為: 1:它會(huì)打開(kāi)模塊的導(dǎo)入段。 2:對(duì)導(dǎo)入段列出的每個(gè)DLL,它會(huì)檢查該DLL文件的文件頭,來(lái)確定該DLL的首選基地址。 3:它會(huì)在DLL的導(dǎo)出段查看每個(gè)符號(hào)。 4:取得符號(hào)的RA
15、V,并將其與模塊的首選基地址相加。得到導(dǎo)入符號(hào)的虛擬地址(VA)。 5:在映像文件的導(dǎo)入段中添加額外信息。這些信息包括映像文件被綁定的各DLL的名稱(chēng),以及各模塊的時(shí)間戳。 在整個(gè)過(guò)程中Bind.exe做了兩個(gè)重要假設(shè): 1:進(jìn)程初始化時(shí)所需的DLL都被映射到了它們的首選基地址。 2:綁定完成之后,DLL導(dǎo)出段所列出的符號(hào)的位置沒(méi)有發(fā)生
16、改變。這可以通過(guò)檢查每個(gè)DLL的時(shí)間戳來(lái)保證。 如果上述假設(shè)有一個(gè)不成立。加載程序必就向綁定之前一樣,手動(dòng)修正可執(zhí)行文件導(dǎo)入段。如果都成立加載程序就可以不用做這些工作了。Dll 預(yù)讀DLL預(yù)加載是指在顯示加載DLL之前,進(jìn)行DLL的預(yù)讀不同系統(tǒng)預(yù)讀方法選取對(duì)性能影響較大,經(jīng)測(cè)試在Win7上用HANDLE file_handle = CreateFileA(file_path,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,OPEN_EXI
17、STING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);這種方式打開(kāi)文件,再用:ReadFile 讀,性能較好。在WinXP上用 適合用這種方式HMODULE dll_module = :LoadLibraryExA(file_path,NULL,LOAD_WITH_ALTERED_SEARCH_PATH | DONT_RESOLVE_DLL_REFERENCES);完整代碼如下:摘自 chrome bool PreReadImage(const char* file_path, size_t size_to_read, size_t step_size);typedef
18、unsigned char uint8;/ A helper function to touch all pages in the range/ base_addr, base_addr + length).void TouchPagesInRange(void* base_addr, size_t length) if (base_addr = NULL) | (length <=0)return ;/ Get the system info so we know the page size. Also, make sure we use a/ non-zero value for t
19、he page size; GetSystemInfo() is hookable/patchable,/ and you never know what shenanigans someone could get up to.SYSTEM_INFO system_info = ;GetSystemInfo(&system_info);if (system_info.dwPageSize = 0)system_info.dwPageSize = 4096;/ We don't want to read outside the byte range (which could tr
20、igger an/ access violation), so let's figure out the exact locations of the first/ and final bytes we want to read.volatile uint8* touch_ptr = reinterpret_cast<uint8*>(base_addr);volatile uint8* final_touch_ptr = touch_ptr + length - 1;/ Read the memory in the range touch_ptr, final_touch_
21、ptr with a stride/ of the system page size, to ensure that it's been paged in.uint8 dummy;while (touch_ptr < final_touch_ptr) dummy = *touch_ptr;touch_ptr += system_info.dwPageSize;dummy = *final_touch_ptr;PIMAGE_DOS_HEADER GetDosHeader(HMODULE module) return reinterpret_cast<PIMAGE_DOS_HE
22、ADER>(module);PIMAGE_NT_HEADERS GetNTHeaders(HMODULE module) PIMAGE_DOS_HEADER dos_header = GetDosHeader(module);return reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<char*>(dos_header) + dos_header->e_lfanew);bool VerifyMagic(HMODULE module) PIMAGE_DOS_HEADER dos_header = Ge
23、tDosHeader(module);if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)return false;PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(module);if (nt_headers->Signature != IMAGE_NT_SIGNATURE)return false;if (nt_headers->FileHeader.SizeOfOptionalHeader !=sizeof(IMAGE_OPTIONAL_HEADER)return false;if (nt_
24、headers->OptionalHeader.Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)return false;return true;bool PreReadImage(const char* file_path, size_t size_to_read, size_t step_size) if (:Util:UI:IsWin7() / Vista+ branch. On these OSes, the forced reads through the DLL actually/ slows warm starts. The solution is
25、 to sequentially read file contents/ with an optional cap on total amount to read.HANDLE file_handle = CreateFileA(file_path,GENERIC_READ,FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);if (file_handle = INVALID_HANDLE_VALUE)return false;/ De
26、fault to 1MB sequential reads.const DWORD actual_step_size = max(static_cast<DWORD>(step_size),static_cast<DWORD>(1024*1024);LPVOID buffer = :VirtualAlloc(NULL,actual_step_size,MEM_COMMIT,PAGE_READWRITE);if (buffer = NULL)return false;DWORD len;size_t total_read = 0;while (:ReadFile(file
27、_handle, buffer, actual_step_size, &len, NULL) &&len > 0 &&(size_to_read ? total_read < size_to_read : true) total_read += static_cast<size_t>(len);:VirtualFree(buffer, 0, MEM_RELEASE);CloseHandle(file_handle); else / WinXP branch. Here, reading the DLL from disk does
28、n't do/ what we want so instead we pull the pages into memory by loading/ the DLL and touching pages at a stride. We use the system's page/ size as the stride, ignoring the passed in step_size, to make sure/ each page in the range is touched.HMODULE dll_module = :LoadLibraryExA(file_path,NUL
29、L,LOAD_WITH_ALTERED_SEARCH_PATH | DONT_RESOLVE_DLL_REFERENCES);if (!dll_module)return false;/base:win:PEImage pe_image(dll_module);if (!VerifyMagic(dll_module)return false;/ We don't want to read past the end of the module (which could trigger/ an access violation), so make sure to check the ima
30、ge size.PIMAGE_NT_HEADERS nt_headers = GetNTHeaders(dll_module);size_t dll_module_length = min(size_to_read ? size_to_read : 0,static_cast<size_t>(nt_headers->OptionalHeader.SizeOfImage);/ Page in then release the module.TouchPagesInRange(dll_module, dll_module_length);FreeLibrary(dll_modul
31、e);return true;二進(jìn)制文件重組PE文件重組是,應(yīng)用程序冷啟過(guò)程中,對(duì)某個(gè)PE文件所有函數(shù)按啟動(dòng)過(guò)程調(diào)用順序進(jìn)行二進(jìn)制重組。重組工具:sawbuck,這是google 提供的一系列工具??稍谠摼W(wǎng)頁(yè)也有原理介紹。首先,先下載sawbuck工具包重組方法如下:1. 先確定要重組的應(yīng)用程序目錄,PE文件,并要有PE文件對(duì)應(yīng)的PDB文件。如:要對(duì)chrome.dll進(jìn)行重組,則還需要準(zhǔn)備chrome.dll.pdb.2. 把 需重組的 PE文件,和對(duì)應(yīng)的PDB,剪切到一個(gè)文件夾下,此文件夾一般與應(yīng)用程序的EXE文件在同一目錄。保證應(yīng)用程序當(dāng)前目錄下, 沒(méi)有要重組的PE文件和對(duì)應(yīng)的PDB.如
32、:把chrome.dll 和 chrome.dll.pdb 移到original 目錄下3. 用sawbuck工具包中的 instrument.exe ,對(duì)chrome.dll 進(jìn)行hook.instrument.exe 是命令行工具,使用如下命令可以對(duì)chrome.dll 進(jìn)行hook,Instrument.exe -input-image=D:Releaseoriginalchrome.dll -output-iamge=D:Releasechrome.dll -mode=calltrace并產(chǎn)生hook后同名的chrom.dll和chrome.dll.pdb.4. 手動(dòng)復(fù)制call_trace_client.dll(在sawbuck工具包中) 到剛產(chǎn)出chrome.dll 相同的目錄如:5. 啟動(dòng)call_trace_service.exe ,命令如下:start call_trace_service.exe start -verbose -trace-dir=traces-trace-dir 指定call_trace_service.exe 的產(chǎn)出目錄,這里是目錄traces, 與call_trace_service.exe 在同一目錄。6.
溫馨提示
- 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 公司植樹(shù)節(jié)親子活動(dòng)方案
- 公司生日感恩策劃方案
- 公司燒烤娛樂(lè)活動(dòng)方案
- 城市交通規(guī)劃與管理的2025年考核試卷及答案
- 2025年心理健康教育課程期末考試試題及答案
- 2025年農(nóng)村經(jīng)濟(jì)與管理綜合能力考試卷及答案
- 2025年金融從業(yè)資格證考試試題及答案
- 2025年非營(yíng)利組織管理師職業(yè)資格考試試卷及答案
- 保衛(wèi)科上半年工作總結(jié)精彩文章
- 2024年度浙江省護(hù)師類(lèi)之主管護(hù)師真題練習(xí)試卷A卷附答案
- 《城市道路照明設(shè)計(jì)標(biāo)準(zhǔn) CJJ45-2015》
- 外研版(一年級(jí)起點(diǎn))小學(xué)英語(yǔ)三年級(jí)下冊(cè)期末測(cè)試卷(含答案及聽(tīng)力音頻-材料)
- 遼寧省丹東市2023-2024學(xué)年八年級(jí)下學(xué)期7月期末歷史試題(無(wú)答案)
- 產(chǎn)業(yè)園企業(yè)服務(wù)規(guī)范及管理辦法模板
- 分部、分項(xiàng)、檢驗(yàn)批劃分
- 飲食基因與文化智慧樹(shù)知到期末考試答案2024年
- MOOC 投資銀行與資本運(yùn)營(yíng)-對(duì)外經(jīng)濟(jì)貿(mào)易大學(xué) 中國(guó)大學(xué)慕課答案
- JJG 707-2014扭矩扳子行業(yè)標(biāo)準(zhǔn)
- 新人教版五年級(jí)小學(xué)數(shù)學(xué)全冊(cè)奧數(shù)(含答案)
- 醫(yī)療器械法規(guī)對(duì)醫(yī)療器械經(jīng)銷(xiāo)商資質(zhì)的規(guī)定
- 安全防水知識(shí)培訓(xùn)內(nèi)容
評(píng)論
0/150
提交評(píng)論