android句柄泄漏
前言
在android開發(fā)過程中,跑一些單元測試,很容易暴露出文件句柄泄漏的問題。前段時間就有這么一個bug,最后確定是文件句柄泄漏的問題。下面我記錄下當(dāng)時一步步如何查找定位句柄泄漏。
正文
首先讓我們看一眼拋錯的log日志。
10-27 00:35:32.141 7437 7437 E AndroidRuntime: FATAL EXCEPTION: main
10-27 00:35:32.141 7437 7437 E AndroidRuntime: Process: com.Android56, PID: 7437
10-27 00:35:32.141 7437 7437 E AndroidRuntime: java.lang.RuntimeException: Could not read input channel file descriptors from parcel.
10-27 00:35:32.141 7437 7437 E AndroidRuntime: at android.view.InputChannel.nativeReadFromParcel(Native Method)
10-27 00:35:32.141 7437 7437 E AndroidRuntime: at android.view.InputChannel.readFromParcel(InputChannel.java:148)
10-27 00:35:32.141 7437 7437 E AndroidRuntime: at android.view.InputChannel$1.createFromParcel(InputChannel.java:39)
這里有一句Could not read input channel file descriptors from parcel,然后我們在這句話的上面又發(fā)現(xiàn)一個有價值的信息。
Caused by: java.io.IOException: Too many open files
通過網(wǎng)上搜索,基本判斷這是一個文件句柄泄漏的問題。
那么我們該如何查找文件句柄泄漏的地方呢。
首先我們需要做到監(jiān)控文件句柄數(shù),由于android是linux的內(nèi)核,所以,系統(tǒng)為每一個進(jìn)程都有一個文件句柄的目錄。
我們先通過ps命令,獲取到我們app的進(jìn)程id。
然后找到一個root過的手機,或者使用andorid模擬器,然后用adb連接到手機,通過shell命令進(jìn)入到/proc/進(jìn)程id/fd這個目錄。由于linux關(guān)于系統(tǒng)的管理都是用文件方式,所以這個文件夾下面就是所有被打開的句柄。
我們可以在app運行的過程中,不斷的進(jìn)入到這個目錄中,然后用ls -l 命令列出所有的文件句柄,這樣就能看到文件句柄有哪些是增長的。然后再根據(jù)不同類型的文件句柄,初步定位是什么在泄漏。
在排查的過程中,為了方便獲取某個進(jìn)程的句柄數(shù),我寫了一個簡單的shell腳本。有需要的同學(xué)可以拿去使用。
echo '查詢進(jìn)程占用文件句柄數(shù)'
set `adb shell ps |grep com.Android56 |grep -v channel |grep -v Daemon`
pidnum=$2
index=0
while true
do
index=$[index+1]
echo '##################'
echo '第'$index'次查詢'
echo '總句柄'
adb shell ls -l /proc/$pidnum/fd |grep "" -c
echo 'anon句柄'
adb shell ls -l /proc/$pidnum/fd |grep anon -c
echo '##################'
sleep 2
done
總結(jié)
通過艱難的排查過程,終于定位到是播放器打開so動態(tài)鏈接庫的時候,一個文件沒有釋放。
具體而言就是,調(diào)用了dlopen、dlsym,但是沒有調(diào)用dlclose這個方法。以后在編程的過程中,一定得多注意這種涉及資源方面的東西。有打開必須有關(guān)閉。同時我建議在測試的過程中,可以加入對文件句柄的監(jiān)控,這樣可以更好的發(fā)現(xiàn)問題,避免線上出bug。