Could not read input channel file descriptors from parcel引發(fā)的句柄泄露問題

最近開發(fā)功能的時(shí)候monkey總是能跑出一個(gè)bug,

java.lang.RuntimeException: Could not read input channel file descriptors from parcel.

百思不得其解,認(rèn)為是系統(tǒng)上面的bug,實(shí)時(shí)證明自己還是太年輕.現(xiàn)在開始分析一下這個(gè)bug產(chǎn)生的原因.

一.為什么會(huì)產(chǎn)生句柄泄露?

眾所周知Android是linux內(nèi)核,也就是可以理解linux下,一切資源都是句柄,每個(gè)進(jìn)程都有自己的句柄上限,而超過了這個(gè)句柄上線,就會(huì)發(fā)生異常.一般android的App都是在單個(gè)進(jìn)程下運(yùn)行的,FD的句柄上限是1024,這個(gè)在后面的會(huì)說明.一切的重點(diǎn)都在proc(Processes,虛擬的目錄,是系統(tǒng)內(nèi)存的映射??芍苯釉L問這個(gè)目錄來獲取系統(tǒng)信息。 )這個(gè)文件夾下的內(nèi)容.

這里有參考The proc File System.

The Linux kernel has two primary functions: to control access to physical devices on the computer and to schedule when and how processes interact with these devices. The /proc/ directory — also called the proc file system — contains a hierarchy of special files which represent the current state of the kernel — allowing applications and users to peer into the kernel's view of the system.

Within the /proc/ directory, one can find a wealth of information detailing the system hardware and any processes currently running. In addition, some of the files within the /proc/ directory tree can be manipulated by users and applications to communicate configuration changes to the kernel.

Linux系統(tǒng)上的/proc目錄是一種文件系統(tǒng),即proc文件系統(tǒng)。與其它常見的文件系統(tǒng)不同的是,/proc是一種偽文件系統(tǒng)(也即虛擬文件系統(tǒng)),存儲(chǔ)的是當(dāng)前內(nèi)核運(yùn)行狀態(tài)的一系列特殊文件,用戶可以通過這些文件查看有關(guān)系統(tǒng)硬件及當(dāng)前正在運(yùn)行進(jìn)程的信息,甚至可以通過更改其中某些文件來改變內(nèi)核的運(yùn)行狀態(tài)。

二.查看進(jìn)程的句柄信息

我們通過proc這個(gè)虛擬文件系統(tǒng),可以獲取到當(dāng)前App的進(jìn)程,然后查看具體的進(jìn)程信息,當(dāng)前App是否存在句柄泄露的問題.具體方法如下.

public class MainActivity extends Activity {

private PageView mPageView;

private Button mButton;

        @Override

        protected void onCreate(Bundle savedInstanceState) {

                super.onCreate(savedInstanceState);

                setContentView(R.layout.activity_main);

                exeCommand("ps");

        }

        private void exeCommand(String command){

                Runtime runtime = Runtime.getRuntime();

                try {

                      Process proc = runtime.exec(command);

                      BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));

                      String line;

                      while ((line = in.readLine()) != null) {

                          System.out.println(line);

                      }

                } catch (IOException e) {

                    e.printStackTrace();

        }

    }

}

這樣我們看到在Android Studio的logcat中打印出了當(dāng)前所有的進(jìn)程號(hào).

進(jìn)程號(hào).png

然后我們繼續(xù)修改我們的代碼.

exeCommand("ps | grep com.behanga");

com.behanga是我測(cè)試App的名字.

app名字.png

這是我們可以看到該App的進(jìn)程號(hào)是16023,也就是說對(duì)應(yīng)在proc中對(duì)應(yīng)的文件夾為/proc/16023/,在這個(gè)文件夾下我們看到當(dāng)前App的信息,好我們繼續(xù)往下查看.
這時(shí)我們打開terminal,輸入

adb shell

進(jìn)入adb shell,然后輸入

cd /proc/16023 && ls -al

現(xiàn)在展示在我們面前的就是當(dāng)前進(jìn)程下信息.


當(dāng)前進(jìn)程的info.png

我們現(xiàn)在可以查看一下當(dāng)前進(jìn)程一些限制.

cat limits
最大打開文件數(shù).png

這里我們看到Max open fils的限制為1024,硬件限制為4096,也就是說我們當(dāng)前打開文件句柄的最大數(shù)為1024.

這時(shí)我們繼續(xù)往下看,因?yàn)槭且治鰂ile descriptors的問題,那么自然要進(jìn)入fd目錄下一看究竟.

cd fd && ls -al
當(dāng)前打開的句柄信息.png

當(dāng)前展示了所在進(jìn)程下所有已經(jīng)被打開的文件句柄.我們可以在當(dāng)前文件夾下統(tǒng)計(jì)所有的句柄總數(shù).

ls | wc -l

這時(shí)打印出所有的句柄總數(shù)為64.這時(shí)我們已經(jīng)完成對(duì)當(dāng)前進(jìn)程的一些句柄信息查看.

三.模擬句柄泄露情況

如果我們要模擬句柄泄漏的情況,我們可以在App中啟動(dòng)一個(gè)HandlerThread,每次在onCreate的時(shí)候HandlerThread.start(),但是在onDestory()時(shí),并不調(diào)用HandlerThread.quit()方法.重復(fù)進(jìn)入.然后在terminal中統(tǒng)計(jì)FD的總數(shù),查看是否有變化,如果FD的總數(shù)一直在增加,就可以確認(rèn)你當(dāng)前App中已經(jīng)出現(xiàn)了句柄泄露的情況.

四.如何避免句柄泄露的發(fā)生

提高對(duì)編碼意識(shí),另外就是monkey的測(cè)試,很多時(shí)候會(huì)發(fā)現(xiàn)一些黑盒測(cè)試無法發(fā)現(xiàn)的問題.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯(cuò)誤還是無法避免 以后資料會(huì)慢慢更新 大...
    數(shù)據(jù)革命閱讀 13,230評(píng)論 2 33
  • 1:InputChannel提供函數(shù)創(chuàng)建底層的Pipe對(duì)象 2: 1)客戶端需要新建窗口 2)new ViewRo...
    自由人是工程師閱讀 5,714評(píng)論 0 18
  • 引言 當(dāng)修改一個(gè)Linux系統(tǒng)參數(shù)或限制,比如文件打開數(shù)時(shí),之前用到過的方式有ulimit、limits.conf...
    bluexiii閱讀 6,445評(píng)論 0 5
  • 摘要:?本文發(fā)現(xiàn)了一類OOM(OutOfMemoryError),這類OOM的特點(diǎn)是崩潰時(shí)java堆內(nèi)存和設(shè)備物理...
    陶菜菜閱讀 51,692評(píng)論 51 357
  • 如果再讓你回到十五年前的學(xué)生時(shí)代,你會(huì)怎么來過?這本身是個(gè)偽命題——時(shí)間過去不待,哪來那么多“如果”。對(duì)于在高樓下...
    Sophie_黃閱讀 511評(píng)論 0 2

友情鏈接更多精彩內(nèi)容