深入學(xué)習(xí)fd泄露問題

最近遇到一個應(yīng)用閃退的問題瘾带,開始發(fā)現(xiàn)問題時沒有找到明顯的問題復(fù)現(xiàn)步驟,單獨操作應(yīng)用里的所有功能都沒有發(fā)生該問題穿挨,而一旦進(jìn)行煲機(jī)測試半小時后出現(xiàn)了月弛。光從應(yīng)用層的log也分析不出問題的原因來,這個問題拖了很長一段時間科盛,真是慚愧!煲機(jī)的業(yè)務(wù)邏輯是通過PC程序循環(huán)發(fā)送指令到車機(jī)板子上菜皂,控制車機(jī)上的測試程序贞绵,調(diào)起測試case執(zhí)行硬件模塊的測試。

問題分析

分析該問題發(fā)生時的log文件恍飘,與我的應(yīng)用有關(guān)的log內(nèi)容主要是正常的業(yè)務(wù)打印榨崩,直到在crash log部分最后有一段包含了我的進(jìn)程名的內(nèi)容,這些log信息甚是可疑章母!

03-03 17:22:16.053  9320  9320 D TestCaseManager: enqueueCase: {mTitle:GPS, mID:GPS, mTestQueueType:OTHER}
03-03 17:22:16.053  9320  9320 D TestCase: secureStart() mStatus=PASS, mID=GPS
03-03 17:22:16.053  9320  9320 V TestCaseManager: onTestResult id:GPS, status:TESTING
03-03 17:22:16.053  9320  9320 D TestCase: secureStart()->invoke the start() of testcase GPS
03-03 17:22:16.055  9320  9320 W zygote64: ashmem_create_region failed for 'indirect ref table': Too many open files
03-03 17:22:16.056  9320 10862 F Looper  : Could not make wake event fd: Too many open files
03-03 17:22:16.057  9320  9320 I GpsUtils: isProviderEnabled:true
03-03 17:22:16.057   598   676 D SocketMoudle: connect: bind failed, try
03-03 17:22:16.138   598   676 D SocketMoudle: connect: bind failed, try
03-03 17:22:16.205   888   961 W DCS_SocketMoudle: connect: accept() error, mCurSockFd=-1, errno=11
03-03 17:22:16.205   888   961 W CanDataProc: rxThread: socket connect retVal: -1
03-03 17:22:16.218   598   676 D SocketMoudle: connect: bind failed, try
03-03 17:22:16.275 10865 10865 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstone
03-03 17:22:16.276   936   936 I /system/bin/tombstoned: received crash request for pid 9320
03-03 17:22:16.277 10865 10865 I crash_dump64: performing dump of process 9320 (target tid = 10862)
03-03 17:22:16.277 10865 10865 I crash_dump64: engrave_tombstone
03-03 17:22:16.277 10865 10865 D DEBUG   : enter engrave_tombstone
03-03 17:22:16.278 10865 10865 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
03-03 17:22:16.278 10865 10865 F DEBUG   : Build fingerprint: 'M01_AE-userdebug-M01.CHJ.A81.M.200225.205'
03-03 17:22:16.278 10865 10865 F DEBUG   : Revision: '0'
03-03 17:22:16.278 10865 10865 F DEBUG   : ABI: 'arm64'
03-03 17:22:16.278 10865 10865 F DEBUG   : pid: 9320, tid: 10862, name: Gps-Handler  >>> com.xxx.car.vehicleeol <<<
03-03 17:22:16.278 10865 10865 F DEBUG   : signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
03-03 17:22:16.295 10865 10865 F DEBUG   : Abort message: 'Could not make wake event fd: Too many open files'
03-03 17:22:16.295 10865 10865 F DEBUG   :     x0   0000000000000000  x1   0000000000002a6e  x2   0000000000000006  x3   0000000000000008
03-03 17:22:16.295 10865 10865 F DEBUG   :     x4   fefeff7c6fd54487  x5   fefeff7c6fd54487  x6   fefeff7c6fd54487  x7   7f7f7f7f7fff7fff
03-03 17:22:16.295 10865 10865 F DEBUG   :     x8   0000000000000083  x9   8d9b2e0bd9a2bbef  x10  0000000000000000  x11  ffffffffffffffff
03-03 17:22:16.295 10865 10865 F DEBUG   :     x12  0000000000000018  x13  ffffffffffffffff  x14  ffffffffff000000  x15  ffffffffffffffff
03-03 17:22:16.295 10865 10865 F DEBUG   :     x16  000000635aa7cfa8  x17  0000007e0d70b5d8  x18  000000000000001a  x19  0000000000002468
03-03 17:22:16.295 10865 10865 F DEBUG   :     x20  0000000000002a6e  x21  0000000000000083  x22  0000007d70d64588  x23  0000000013640100
03-03 17:22:16.295 10865 10865 F DEBUG   :     x24  0000000000000008  x25  0000007d70d64588  x26  0000007d5f2f6ea0  x27  0000000000000002
03-03 17:22:16.295 10865 10865 F DEBUG   :     x28  0000000000000002  x29  0000007d70d63090  x30  0000007e0d6bebbc
03-03 17:22:16.295 10865 10865 F DEBUG   :     sp   0000007d70d63050  pc   0000007e0d6bebdc  pstate 0000000060000000
03-03 17:22:16.299   598   676 D SocketMoudle: connect: bind failed, try
03-03 17:22:16.379   598   676 D SocketMoudle: connect: bind failed, try

看到這樣的log母蛛,對于年幼無知的我,感到一臉蒙逼叭樵酢彩郊!在百度上谷歌一下Too many open files,這個問題涉及到Linux系統(tǒng)文件句柄超限蚪缀,是Linux進(jìn)程的fd泄露問題秫逝,這是什么鬼?得好好研究一下了询枚!
繼續(xù)分析上面問題發(fā)生的原因违帆,上面的log中打印 Could not make wake event fd: Too many open files這句log之前有一句打印是

pid: 9320, tid: 10862, name: Gps-Handler >>> com.xxx.car.vehicleeol <<<

可以發(fā)現(xiàn)是進(jìn)程com.xxx.car.vehicleeol里的線程Gps-Handler引起了fd泄露的問題,搜索代碼金蜀,在我的工程里發(fā)現(xiàn)了如下創(chuàng)建這個線程的方法:

init()這個方法會在每次執(zhí)行GPS檢測項時調(diào)用刷后,GPS檢測結(jié)束后會將mLocateOn設(shè)置為false,所以每次執(zhí)行這個方法均會執(zhí)行創(chuàng)建HandlerThread的代碼渊抄,前文說的煲機(jī)測試就是一遍一遍地執(zhí)行這些測試項尝胆。上面問題發(fā)生的原因應(yīng)該就在這里了,應(yīng)用進(jìn)程在不斷地創(chuàng)建HandlerThread對象抒线,并執(zhí)行start()班巩。

為什么HandlerThread與fd泄露有關(guān)系?fd究竟在Linux OS中是什么?發(fā)生fd泄露的問題應(yīng)該如何解決呢抱慌?借著解決這個問題的機(jī)會逊桦,我?guī)е@些疑惑深入學(xué)習(xí)一下fd泄露的問題。

fd真相揭秘

Fd的全稱是File descriptor抑进,在Linux OS里强经,所有都可以抽象成文件,比如普通的文件寺渗、目錄匿情、塊設(shè)備、字符設(shè)備、socket、管道等等胁澳。當(dāng)通過一些系統(tǒng)調(diào)用(如open/socket等)踏拜,會返回一個fd(一個數(shù)字),然后根據(jù)這個fd對應(yīng)的文件進(jìn)行操作,比如讀、寫。在內(nèi)核進(jìn)程結(jié)構(gòu)體task_struct中為每個進(jìn)程維護(hù)了一個數(shù)組跷车,數(shù)組下標(biāo)就是fd,里面存儲的是對這個文件的描述橱野。

Linux默認(rèn)每個進(jìn)程能打開的fd數(shù)最大值是1024朽缴,當(dāng)應(yīng)用進(jìn)程打開的文件數(shù)超過這個限制值后就無法再打開文件了,系統(tǒng)會報相關(guān)的錯誤水援,Too many open files是Linux系統(tǒng)中程序打開的文件數(shù)過多的常見錯誤密强。

對于HandlerThread,我知道它實際上是一個Thread加上了一個Looper裹唆,在其run()方法中調(diào)用Looper.prepare()和Looper.loop()方法誓斥,這樣就可以在子線程中運行Handler的handlerMessage方法進(jìn)行消息處理了,這是之前對HandlerThread的淺顯的認(rèn)識许帐。繼續(xù)跟蹤源碼發(fā)現(xiàn)每一個Looper在創(chuàng)建的時候會打開兩個fd劳坑,一個是eventfd,另外一個是mEpolled成畦。上面問題中報的就是創(chuàng)建wake event fd時異常了距芬。


fd是系統(tǒng)底層邏輯創(chuàng)建的,要修復(fù)這個問題應(yīng)該控制上層應(yīng)用邏輯循帐,避免引起fd創(chuàng)建過多框仔。對上面由HandlerThread引起的fd泄露問題如下修改,最終解決了問題拄养。

搜索網(wǎng)上對這個問題的分析和解決离斩,產(chǎn)生Too many open files問題主要有四種可能:
1银舱、單個進(jìn)程打開文件句柄數(shù)過多
2、操作系統(tǒng)打開的文件句柄數(shù)過多
3跛梗、systemd對該進(jìn)程進(jìn)行了限制
4寻馏、inotify達(dá)到上限

上面四種產(chǎn)生fd泄露的情況我歸納為兩方面的原因,一是系統(tǒng)本身限制了可操作的文件句柄數(shù)核偿,二是應(yīng)用的邏輯問題導(dǎo)致文件句柄超出了系統(tǒng)設(shè)定的限制诚欠。要解決fd泄露的問題,一方面可以通過修改系統(tǒng)參數(shù)漾岳,增大允許操作的文件句柄數(shù)轰绵;另一方面修改應(yīng)用程序內(nèi)部邏輯,使得程序在運行時不會超過系統(tǒng)允許的最大文件句柄數(shù)尼荆。

fd泄露其他案例

可能引起fd泄露問題的情況有多種左腔,fd泄露問題的主要特點是:
1、同一個問題可能出現(xiàn)在不同的堆棧
2耀找、fd發(fā)生泄露時可能不存在內(nèi)存不足的問題翔悠,觸發(fā)GC不一定能回收創(chuàng)建的文件句柄

fd泄露問題的關(guān)鍵日志:

"Too many open files"
"Could not allocate JNI Env"
"Could not allocate dup blob fd"
"Could not read input channel file descriptors from parcel"
"pthread_create"
"InputChannel is not initialized"
"Could not open input channel pair"

容易引起fd泄露的常見情況:
1、HandlerThread
如前文分析野芒,HandlerThread引發(fā)的fd泄露是由于頻繁地創(chuàng)建HandlerThread對象,內(nèi)部的Looper創(chuàng)建會導(dǎo)致fd超限双炕。
2狞悲、Thread.start()
調(diào)用Thread.start()啟動線程后,在native層調(diào)用open方法創(chuàng)建ashmem rigions妇斤,這會產(chǎn)生fd摇锋,如果循環(huán)地創(chuàng)建啟動過多的線程就會產(chǎn)生fd泄露。
3站超、Resource相關(guān)
使用輸入輸出流沒有關(guān)閉可能會出問題荸恕,F(xiàn)ileInputStream、FileOutputStream死相、FileReader融求、FileWriter 等每打開一個文件需要fd,一些輸入流也提供了基于fd的構(gòu)造方法算撮。文件流在finally塊中調(diào)close方法生宛,或者使用Java 7 編譯器和運行環(huán)境支持的 try-with-resources 語句可以避免fd泄露。
4肮柜、InputChannel
對于system server,陷舅,如果有大量的socket 打開,可能是因為Input Channel沒有關(guān)閉审洞,抓取hprof查看system server中WindowState的情況進(jìn)行分析莱睁。
5、Bitmap
創(chuàng)建Bitmap在native層會產(chǎn)生fd,如果使用完后不關(guān)閉仰剿,可能引發(fā)fd的泄露创淡。

Thanks To

Too many open files的四種解決辦法
too many open files(打開的文件過多)解決方法
Linux中Too many open files 問題分析和解決
應(yīng)用與系統(tǒng)穩(wěn)定性第三篇---FD泄露問題漫談

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市酥馍,隨后出現(xiàn)的幾起案子辩昆,更是在濱河造成了極大的恐慌,老刑警劉巖旨袒,帶你破解...
    沈念sama閱讀 221,888評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汁针,死亡現(xiàn)場離奇詭異,居然都是意外死亡砚尽,警方通過查閱死者的電腦和手機(jī)施无,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來必孤,“玉大人猾骡,你說我怎么就攤上這事》筇拢” “怎么了兴想?”我有些...
    開封第一講書人閱讀 168,386評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長赡勘。 經(jīng)常有香客問我嫂便,道長,這世上最難降的妖魔是什么闸与? 我笑而不...
    開封第一講書人閱讀 59,726評論 1 297
  • 正文 為了忘掉前任毙替,我火速辦了婚禮,結(jié)果婚禮上践樱,老公的妹妹穿的比我還像新娘厂画。我一直安慰自己,他們只是感情好拷邢,可當(dāng)我...
    茶點故事閱讀 68,729評論 6 397
  • 文/花漫 我一把揭開白布袱院。 她就那樣靜靜地躺著,像睡著了一般解孙。 火紅的嫁衣襯著肌膚如雪坑填。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,337評論 1 310
  • 那天弛姜,我揣著相機(jī)與錄音脐瑰,去河邊找鬼。 笑死廷臼,一個胖子當(dāng)著我的面吹牛苍在,可吹牛的內(nèi)容都是我干的绝页。 我是一名探鬼主播,決...
    沈念sama閱讀 40,902評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼寂恬,長吁一口氣:“原來是場噩夢啊……” “哼续誉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起初肉,我...
    開封第一講書人閱讀 39,807評論 0 276
  • 序言:老撾萬榮一對情侶失蹤酷鸦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后牙咏,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體臼隔,經(jīng)...
    沈念sama閱讀 46,349評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,439評論 3 340
  • 正文 我和宋清朗相戀三年妄壶,在試婚紗的時候發(fā)現(xiàn)自己被綠了摔握。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,567評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡丁寄,死狀恐怖氨淌,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情伊磺,我是刑警寧澤盛正,帶...
    沈念sama閱讀 36,242評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站屑埋,受9級特大地震影響蛮艰,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜雀彼,卻給世界環(huán)境...
    茶點故事閱讀 41,933評論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望即寡。 院中可真熱鬧徊哑,春花似錦、人聲如沸聪富。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,420評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽墩蔓。三九已至梢莽,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間奸披,已是汗流浹背昏名。 一陣腳步聲響...
    開封第一講書人閱讀 33,531評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留阵面,地道東北人轻局。 一個月前我還...
    沈念sama閱讀 48,995評論 3 377
  • 正文 我出身青樓洪鸭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親仑扑。 傳聞我的和親對象是個殘疾皇子览爵,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,585評論 2 359

推薦閱讀更多精彩內(nèi)容