當程序的子模塊數量和規模擴大以後,在開發階段,系統長時間容許後常常會碰到下面一些bug:程序員
調試這些問題,固然能夠從代碼流程和邏輯出發,結合ps/gdb/proc/core等命令和信息,一步步挖出root cause。但通常要求對代碼、線程關係和相關命令比較熟悉,通常耗時較長。因此,通常大型公司都封裝了標準的glibc,作了一個wraaper,而後再wrapper裏面加入了對上面調試的支持。還有的可採用專業內存泄漏等檢查工具,去作代碼檢測。那麼,對於咱工程師而言,可否能本身設計並實現一個資源檢查工具呢?數據結構
針對上面的三個例子使用中的資源,咱們能夠概括成兩類:數量有限的共享資源,好比上面空間有限的內存和數量有限的文件句柄;須要獨佔的互斥資源,好比上面例子中提到的鎖。 下面就分別針對這兩種狀況,分別展開分析。app
共享資源的特色是:總量有限,經過申請接口得到,使用完了以後經過釋放接口歸還。爲了保證不浪費資源,這就要求程序在使用完了申請獲得的資源以後,必須及時釋放。而共享資源出現問題的狀況,大部分是因爲程序員遺忘沒有釋放形成的。所以,須要一種內部機制可以記錄哪些資源使用了尚未釋放,能夠經過下面的步驟實現:ide
獨享資源的特色是:互斥使用,基本上是先到先得,經過標誌設置是否以備佔有。爲了保證不死鎖,這就要求:程序在申請某個互斥資源的時候,須要檢查它已經擁有的資源,是否被它正在申請的互斥資源的擁有者申請。
若是是,會死鎖;不然,不會死鎖。一樣也能夠經過下面的步驟實現:函數
根據上面原理的分析,咱們不難結合以前講過的xlink、程序堆棧等技巧,選用合適的數據結構來實現。工具
根據2.1中的分析,須要先構造一張表來記錄這些資源的地址,這張表要求插入方便,刪去也迅速。爲此,咱們能夠用基於平衡二叉樹、優先級隊列或者hash的方法去實現這個表。對這個表的操做包括PQInsert()/PQRemove()/PQEmpty()等。 此後,就能夠開始參考下面列出的針對共享資源泄漏檢查的步驟去實現了。線程
能夠基於標準的open/close/malloc/free等直接申請、是否公共資源的函數,去實現wrapper。
下面以open()、close()爲例,僞碼示例以下:
int wrapper_open(char * dev);
int wrapper_free(int fd);設計
仍是下面以open()、close()爲例:調試
#define FILE ('f'<<24|'i<<16|'l'<<8|'e') int wrapper_open(char * dev) { int fd = real_open(dev); PQInsert(FILE, fd); return fd; } int wrapper_close(int fd) { int ret = 0; PQRemove(FILE, fd); ret = real_close(fd); return ret; }
有兩種方式可使用支持資源泄漏檢查的wrapper函數,一種是代碼中之間調用open/close等函數對應的wrapper函數,另一種是藉助gcc Xlink 的支持讓標準的open/close函數「重定向」到wrapper_open/wrapper_close函數。顯然,後面一種方法工做量最小、最優雅。具體的實現,能夠參考前面關於Xlink的博文,下面列出了主要的幾個步驟:code
gcc編譯的flag中加入Xlinker改動
Xlinker --wrap=open -Xlinker --undefined=wrapper_open Xlinker --wrap=close -Xlinker --undefined=wrapper_close
新的頭文件中加入聲明
typeof(open) wrapper_open; typeof(close) wrapper_close; typeof(open) real_open; typeof(close) real_close;
一般,在程序快要結束退出的時候,會釋放資源,末了能夠經過共享資源泄漏檢查函數去檢查是否正的有資源泄漏。這個函數的主要實現的示例以下:
int FileRes_check(void) { if PQEmpty(FILE) { return PASS; } esle { PQDump(FILE); return FAIL; } }
根據上一篇博文中,關於如何獲得程序堆棧中介紹的方法,咱們能夠在申請共享資源的時候,具體來講就是調用PQInsert(FILE, fd)時,取得當前程序的stack, 把堆棧信息和fd一塊兒做爲一項紀錄插入到基於優先級隊列、散列或者平衡二叉樹實現的表中去。 一樣,PQDump()除了打印沒有關閉的文件句柄以外,還輸出這個句柄對應打開時候的程序堆棧,根據這個堆棧信息,程序員可以定位到打開了這個沒被關閉的句柄的代碼的位置。而一般,這個句柄的關閉應該在它以後附近。
對獨享資源死鎖的檢查的具體實現依賴的技術同上,差異就在死鎖檢查的邏輯和流程。讀者能夠自行嘗試,等有時間了我也能夠再來完善。
經過上面的這麼多介紹能夠看到,基於對共享資源和互斥資源使用特色的分析,咱們可以提出一種針對共享資源泄漏和獨享資源死鎖檢查的通用原理。藉助於合適的數據結構(二叉樹、優先級隊列或散列),基於 Xlinker方法、堆棧獲取的API,咱們可以實現一種輕巧的、幾乎不用改動已有代碼的對開發者很是友好的資源檢查功能。