




版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領
文檔簡介
1、客戶端做到一定程度,都會做啟動優(yōu)化,啟動優(yōu)化主要有如下方式1、 dll 基址固定2、 dll 延遲加載3、 dll 文件預讀4、 程序二進制文件連續(xù)分布5、 二進制文件relink6、 啟動邏輯優(yōu)化調(diào)整客戶端性啟動性能優(yōu)化比起服務器要簡單,服務器動不動就搞緩存、分布式、算法調(diào)優(yōu)、客戶端啟動優(yōu)化說來說去,核心思想不過下幾點1、 減少文件io2、 減少page fault 3、 減少磁盤跨磁道操作4、 啟動邏輯前移,先顯示ui,后加載邏輯涉及到的工具1、 process monitor 查看啟動的時候file io2、 xpref 分析啟動的時候性能,消耗時間的部分在哪塊3、 wcontig 查看
2、文件碎片的小工具4、 sawbuck, 這是google 提供的一系列二進制重組工具。用了這些方法和工具后,完全可以忽略掉微軟的prefetcher,這個工具1不開源,其次資料非常少,能起到的作用也有限,微軟只會用閉源這一招,但是比他強大的方法實在太多。重點講下 基址固定,dll文件預讀,二進制relink,二進制文件磁盤整理基址固定: 每個DLL和可執(zhí)行文件都有一個首選基地址。它表示該模塊被映射到進程地址空間時最佳的內(nèi)存地址。在構建可執(zhí)行文件時,默認情況下鏈接器會將它的首選基地址設為0x400000。對于DLL來說,鏈接器會將它的首選基地址設為0x1000
3、0000,然后將該地址以及代碼、數(shù)據(jù)的相關地址都寫入它們的PE文件中。當它們被加載時,加載程序讀取首選基地址的值,并試圖把它們加載到相應位置。 對于可執(zhí)行文件和DLL中的代碼,它們運行的時候所引用的的數(shù)據(jù)的地址,在鏈接的時候就已經(jīng)確定。并且這些都是當exe文件或是DLL被加載到它們的首選基地址處時才是有效的。 對于匯編代碼:MOV 0x00414540 ,5 它是將5賦值給0x00414
4、540處的內(nèi)存地址。此地址已經(jīng)固定。它說明當EXE或是DLL被加載到0x400000處時,0x00414540才是正確的。然而并不是所有模塊都會被載入到首選基地址處。一旦模塊沒有被加載到首選基地址處,在該模塊中對于地址的引用都是錯誤的,這時候基址重定位就是必須的。所謂重定位就是當某模塊未被載入到首選基地址時,加載器會計算模塊實際載入的地址跟首選基地址的差值,將這個差值加到機器指令所引用的原來的地址,得到的就是模塊中各指令所引用的數(shù)據(jù)在本進程地址空間的正確地址,隨后加載器會修正模塊中對每個內(nèi)存地址的引用。 為了便
5、于系統(tǒng)有能力對各數(shù)據(jù)的地址進行修正,windows提供了重定位段。它包含很多基址重定位信息。這個段是有很多項組成。每一項表示一個要重定位的地址,它包含一個字節(jié)偏移量列。該偏移量表示一條機器指令所使用的內(nèi)存地址。這便于系統(tǒng)在確認該模塊需要重定位時對需要重定位的數(shù)據(jù)進行定位。 當鏈接器在構建模塊時,它會將重定位段嵌入到生成的文件中。 對exe文件來說,由于每個文件總是使用獨立的地址空間,所以exe文件總是可以被加載到首選基地址上。對于DLL來說
6、,很多DLL都是使用寄主進程的地址空間,不能保證各DLL的首選基地址各不相同。所以DLL一定要有重定位段,除非在鏈接時使用/FIXED 開關。此時鏈接器會去掉重定位段。如果此后模塊未被載入首選基地址,由于無法重定位,模塊不會被載入,導致程序無法運行。 如果加載程序將模塊加載到它的首選基地址,那么系統(tǒng)就不會訪問模塊的重定位段。否則系統(tǒng)會打開模塊的重定位段并遍歷其中的條目,對每個條目,加載程序先找到包含機器指令的那個存儲頁面,算出差值,將差值加到機器指令當前正在使用的內(nèi)存地址上。 &
7、#160; 對于上例:假如它是在一DLL中。如果該DLL實際被加載到0x20000000處,由于首選基地址是0x10000000,兩者差為0x10000000。加載器修正之后,該指令所引用的實際地址變成了0x10414540。這樣對各個數(shù)據(jù)的引用都會引用到正確的地址 。 要知道基址重定位需要很大的系統(tǒng)開銷: 1:加載程序需要遍歷模塊重定位段并修改模塊中大量的代碼。這增加了程序初始化時間。
8、0; 2:當加載程序寫入模塊的代碼頁面時,由于它們具有寫時復制屬性,寫時復制機制會導致系統(tǒng)從頁交換文件中分配空間來容納這些修改后的頁面。 明白了這些我們應該清楚,為每個映射到進程的DLL設置不同的首選基地址是必須的。在鏈接時,選中ProjectPropertiesLinkerAdvancved,然后在BaseAddress中設置。這聽起來很容易,但是如果程序需要載入大量的模塊,我們還需要這樣一個一個設置嗎?話又說回來了,有些模塊并不是我們創(chuàng)建的,我們應該怎么辦呢? &
9、#160; Windows為我們提供了一個名為:Rebase.exe的工具。 如果在執(zhí)行它時為它提供一組映像文件名,它會執(zhí)行以下操作: 1:它會模擬創(chuàng)建一個地址空間。 2:它會打開這一組映像文件,并得到它們的大小和首選基地址。 3:它會在模擬的地址空間對模塊重定位的過程進行模擬,以便各模塊沒有交叉。 4:對于每個需要重定位的模塊,它會解析模塊的重定位段,并修
10、改模塊在磁盤文件中的代碼。 5:將每個模塊新的首選基地址寫入各個模塊磁盤文件中。 所以推薦你在構建完所有項目后運行Rebase.exe。 由于Microsoft在發(fā)布windows之前,已經(jīng)使用Rebase.exe對所有操作系統(tǒng)提供的模塊進行了重定位,所以即使將操作系統(tǒng)的所有模塊都映射到進程地址空間也不會發(fā)生交叉的現(xiàn)象。我們不再需要對隨操作系統(tǒng)一起發(fā)布的模塊進行基址重定位。 使用R
11、ebase.exe或是手工修改各模塊的首選基地址,以免某些模塊不被加載到首選基地址上。這當然可以提高系統(tǒng)性能。但是我們還可以更顯著的提高性能。 這種技術就是模塊綁定。 讓我們來回顧一下程序加載模塊的過程: 加載程序首先為進程創(chuàng)建虛擬地址空間,接著把可執(zhí)行文件映射進來。之后打開可執(zhí)行文件的導入段,將該程序需要的DLL進行定位并把它們也載入進來。隨著加載程序將DLL模塊加載到進程地址空間,它會同時檢查每個DL
12、L的導入段。如果一個DLL有導入段,那么加載程序會繼續(xù)將所需的額外的DLL模塊映射到進程地址空間。當所有DLL都已被載入進程地址空間,它開始修復所有對導入符號的引用。這時它會再次查看每個模塊的導入段,對導入段中每個符號,它會檢查對應DLL的導出段,然后取出該符號的RVA并給他加上DLL模塊被載入到進程地址空間的虛擬地址。計算出符號在進程的虛擬地址(VA),寫入到可執(zhí)行模塊的導入段中。這樣當一個符號被引用的時候,程序會查看可執(zhí)行模塊的導入段并取得導入符號虛擬地址(VA)。 這就是模塊加載的大概過程??梢钥吹?,每次
13、在程序加載時,都要將導入段的符號地址從其他DLL中獲得,然后寫入到導入段的相應位置(IAT)。這十分耗費時間。 所謂的模塊綁定就是說在運行之前,所有導入符號在進程地址空間的地址已經(jīng)獲得,不需要加載時在計算出來這節(jié)省初始化時間,另外將導入符號的虛擬地址寫入exe模塊的導入段,也會由于寫時復制機制將要修改的頁面以系統(tǒng)頁交換文件為后備存儲器。這會遇到與基址重定位相似的問題。所以模塊綁定對提高系統(tǒng)性能的提高是顯著的。 VisualStudio提供了一個名為Bin
14、d.exe的工具,如果在執(zhí)行它的時候傳給它一個映像文件名,它會對其執(zhí)行模塊綁定操作。 具體過程為: 1:它會打開模塊的導入段。 2:對導入段列出的每個DLL,它會檢查該DLL文件的文件頭,來確定該DLL的首選基地址。 3:它會在DLL的導出段查看每個符號。 4:取得符號的RA
15、V,并將其與模塊的首選基地址相加。得到導入符號的虛擬地址(VA)。 5:在映像文件的導入段中添加額外信息。這些信息包括映像文件被綁定的各DLL的名稱,以及各模塊的時間戳。 在整個過程中Bind.exe做了兩個重要假設: 1:進程初始化時所需的DLL都被映射到了它們的首選基地址。 2:綁定完成之后,DLL導出段所列出的符號的位置沒有發(fā)生
16、改變。這可以通過檢查每個DLL的時間戳來保證。 如果上述假設有一個不成立。加載程序必就向綁定之前一樣,手動修正可執(zhí)行文件導入段。如果都成立加載程序就可以不用做這些工作了。Dll 預讀DLL預加載是指在顯示加載DLL之前,進行DLL的預讀不同系統(tǒng)預讀方法選取對性能影響較大,經(jīng)測試在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);這種方式打開文件,再用: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;二進制文件重組PE文件重組是,應用程序冷啟過程中,對某個PE文件所有函數(shù)按啟動過程調(diào)用順序進行二進制重組。重組工具:sawbuck,這是google 提供的一系列工具??稍谠摼W(wǎng)頁也有原理介紹。首先,先下載sawbuck工具包重組方法如下:1. 先確定要重組的應用程序目錄,PE文件,并要有PE文件對應的PDB文件。如:要對chrome.dll進行重組,則還需要準備chrome.dll.pdb.2. 把 需重組的 PE文件,和對應的PDB,剪切到一個文件夾下,此文件夾一般與應用程序的EXE文件在同一目錄。保證應用程序當前目錄下, 沒有要重組的PE文件和對應的PDB.如
32、:把chrome.dll 和 chrome.dll.pdb 移到original 目錄下3. 用sawbuck工具包中的 instrument.exe ,對chrome.dll 進行hook.instrument.exe 是命令行工具,使用如下命令可以對chrome.dll 進行hook,Instrument.exe -input-image=D:Releaseoriginalchrome.dll -output-iamge=D:Releasechrome.dll -mode=calltrace并產(chǎn)生hook后同名的chrom.dll和chrome.dll.pdb.4. 手動復制call_trace_client.dll(在sawbuck工具包中) 到剛產(chǎn)出chrome.dll 相同的目錄如:5. 啟動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. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 互聯(lián)網(wǎng)平臺服務合作協(xié)議
- 項目管理中的經(jīng)濟數(shù)據(jù)分析方法試題及答案
- 2025年市政工程環(huán)境評估試題及答案
- 分類匯編試題及答案
- 水利水電工程試題及答案詳解
- 制勝關鍵的市政工程試題及答案
- 市政工程課程設置試題及答案
- 水利水電工程在國際合作中的角色及試題及答案
- 過期租房合同后果
- 課程材料采購合同
- 實驗 驗證牛頓第二定律
- 鉆孔水文地質工程地質綜合編錄一覽表模板
- 備用柴油發(fā)電機定期啟動試驗記錄表
- 國企食堂運作方案
- 二年級上冊心理健康教育說課稿-面對批評 全國通用
- 工程管理檢討書
- 勞務派遣合同示范文本(4篇)
- 2023年廣西賀州中考語文真題及答案
- 押運員崗位職責
- 2008年安徽省中考英語試卷及答案
- 眼動的檢查與訓練
評論
0/150
提交評論