let's make dependency walker fast again
let's make dependency walker fast again
緣起
最近,經常需要調查 dll 加載失敗的問題。前一陣子剛分享了一篇,感興趣的小伙伴而可以點擊 這里。相信,有 windows 開發經驗的小伙伴兒一定聽過 Dependency Walker 這款工具,它可是查看模塊依賴關系的神兵利器。但是在我的機器上,Dependency Walker 運行的特別慢,經常無響應!慢了這么久,是時候提提速了。
重現問題
很容易就可以重現問題,隨便拖動一個 dll 文件(或者 exe 文件)到 Dependency Walker 中,等大概 5 秒鐘,就會出現大名鼎鼎的無響應界面,需要等待很久才能等到分析結果。

探查敵情
在大動干戈之前,先用 process explorer 粗略查看 Dependency walker 中各個線程的運行情況。

看來,只有一個線程在工作(其它兩個線程是系統工作線程),也是界面線程。如果界面線程都用來處理其它工作,長時間沒有處理界面消息的話,界面就會無響應。
從調用棧可知,Dependency Walker 在運行過程中會不斷的調用 SearchPath 和 FindFirstFile。從這兩個函數的名字可以猜測是在搜索文件。
如果有超多文件需要搜素,那么整個過程慢是合理的。只從 process explorer 中并不能知道 Dependency Waler 在搜索哪些文件,在哪些地方搜索。
小貼士:使用
process explorer的線程功能,可以很方便的快速定位一些問題,如有必要,再上調試器進行分析。
process monitor
觀察進程文件操作記錄對于 process monitor 來說簡直是小菜一碟。因為預計時間會比較長,而且只需要關心 Dependency Walker 相關的事件,所以在開始前,先做好過濾。
拖動 process monitor 上的靶子圖標到 Dependency Walker 上,表示只關心當前這個 Dependency Walker 實例相關的事件。勾選 Drop filtered Event 表示丟棄過濾的事件,因為會過濾掉大部分無關的事件,生成的記錄文件會比較小,可以記錄更多有用的事件。

等 Dependency Walker 完成分析后,停止記錄,查看文件相關事件。 dll 相關的事件一共有 247688 條。
好奇我是怎么知道的?請看下圖:

觀察一個比較典型的文件( api-ms-win-core-rtlsupport-l1-1-0.dll)的相關記錄。該文件相關的事件數量是 908 條。

該文件相關的部分事件截圖如下:

在上圖中,可以很明顯的看到 Result 列大部分結果不是 Success。這個在意料之中,因為正常情況下這個 dll 應該只在特定路徑下才有。從 Path 列中的記錄可知,搜索路徑有很多個。
深入觀察
如果仔細觀察,可以發現搜索路徑非常像典型的 Dll 搜索路徑。Dll 搜索路徑的官方參考資料鏈接為 https://docs.microsoft.com/zh-cn/windows/win32/dlls/dynamic-link-library-search-order?redirectedfrom=MSDN。
為了方便大家查看,我截取了相關部分,如下圖:

我機器上的 PATH 環境變量如下圖:

如此看來,Dependency Walker 正是按照典型的 Dll 搜索路徑在查找啊(默認情況,可以修改)!
通過上面的簡單分析,可以初步判定:除了把應該寫在工作線程的代碼寫在 UI 線程有點問題,其它地方沒有明顯問題,確實有很多工作需要處理。
只能從減少搜索路徑的方向著手了。如果可以少搜索一些地方,那么工作量會顯著下降,速度相應的會提高上來了。我第一個想到的辦法就是改變 PATH 環境變量的值。
手動設置 PATH
最簡單的辦法是,設置 PATH 環境變量的值為空,這樣就可以避免搜索 PATH 環境變量指定的相關路徑了。如果調整全局的 PATH 環境變量會影響所有程序,不可取。但是可以通過腳本啟動 Dependency Walker ,在啟動 Dependency Walker 之前,設置 PATH 為空,這樣只會影響 Dependency Walker。保存下面的批處理腳本為 start_depends.bat,雙擊運行即可。
set PATH=""
"C:\My\tools\DEPENDS\x64\Depends.exe"通過以上腳本啟動的 Dependency Walker 眼中的 PATH 是空。
如果再次拖動相同的文件到 Dependency Walker 中,基本上是秒出結果。如下圖:

在修改 PATH 環境變量之前,大概需要 2 分鐘左右才能看到結果,而現在只需要用 1 秒左右,是不是不止快了 100 倍呢?對于一些依賴更加復雜的程序,效率提升的會更加明顯!
小貼士:只有確定不會從
PATH中加載對應的DLL,才可以設置PATH為空。既然可以設置PATH為空,就可以設置PATH為任意值。
但是,這樣的操作終究有些不自然。難道,Dependency Walker 本身就不支持設置搜索路徑嗎?
Dependency Walker 設置
簡單的瀏覽了一遍 Dependency Walker 的菜單,發現可以通過 Options -> Configure Module Search Order... 來設置模塊搜索順序及搜索路徑。

設置界面如下圖:

可以根據自己的需要進行設置。
小貼士:
The system's ’PATH‘ environment variable directories指的是系統PATH環境變量對應的路徑,排除它,效果與把PATH設置成空一樣。
總結
-
Dependency Walker可以自定義搜索目錄,合理設置搜索目錄,會大大提高搜索速度!默認情況下,
Dependency Walker會搜索PATH指定的路徑,所以也可以通過修改PATH環境變量的值達到相同的效果。 -
如果長時間(大概
5秒鐘)沒有處理界面消息的話,界面就會無響應。

浙公網安備 33010602011771號