Too many open files問題
在做項目中,遇到這樣一個問題Too many open files:
01-15 23:35:56.481 W/System.err(18683): java.io.FileNotFoundException: /data/data/xxx/C2BD95DBA8137A69CAE53D3B34886395: open failed: EMFILE (Too many open files)
01-15 23:35:56.483 W/System.err(18683): at libcore.io.IoBridge.open(IoBridge.java:416)
01-15 23:35:56.483 W/System.err(18683): at java.io.FileInputStream.<init>(FileInputStream.java:78)
01-15 23:35:56.483 W/System.err(18683): at java.io.FileReader.<init>(FileReader.java:42)
**01-15 23:35:56.487 W/System.err(18683): Caused by: libcore.io.ErrnoException: open failed: EMFILE (Too many open files)**
01-15 23:35:56.488 W/System.err(18683): at libcore.io.Posix.open(Native Method)
01-15 23:35:56.489 W/System.err(18683): at libcore.io.BlockGuardOs.open(BlockGuardOs.java:110)
01-15 23:35:56.489 W/System.err(18683): at libcore.io.IoBridge.open(IoBridge.java:400)
提示說檔案打開數量過多了。由于打開額檔案過多,超出系統的最高限度,核心不再讓其打開檔案了。是以再打開任何檔案就是失敗的。
後續通路檔案、socket連接配接請求等都會出現很多異常。如出現以下異常(Caused by: android.os.TransactionTooLargeException:可能原因之一就是打開檔案過多):
01-16 06:01:52.077 E/CrashHandler(32551): FATAL EXCEPTION:
01-16 06:01:52.077 E/CrashHandler(32551): java.lang.RuntimeException: Adding window failed
01-16 06:01:52.077 E/CrashHandler(32551): at android.view.ViewRootImpl.setView(ViewRootImpl.java:545)
01-16 06:01:52.077 E/CrashHandler(32551): at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:246)
01-16 06:01:52.077 E/CrashHandler(32551): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
01-16 06:01:52.077 E/CrashHandler(32551): at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2806)
01-16 06:01:52.077 E/CrashHandler(32551): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2235)
01-16 06:01:52.077 E/CrashHandler(32551): at android.app.ActivityThread.access$600(ActivityThread.java:141)
01-16 06:01:52.077 E/CrashHandler(32551): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
01-16 06:01:52.077 E/CrashHandler(32551): at android.os.Handler.dispatchMessage(Handler.java:99)
01-16 06:01:52.077 E/CrashHandler(32551): at android.os.Looper.loop(Looper.java:137)
01-16 06:01:52.077 E/CrashHandler(32551): at android.app.ActivityThread.main(ActivityThread.java:5041)
01-16 06:01:52.077 E/CrashHandler(32551): at java.lang.reflect.Method.invokeNative(Native Method)
01-16 06:01:52.077 E/CrashHandler(32551): at java.lang.reflect.Method.invoke(Method.java:511)
01-16 06:01:52.077 E/CrashHandler(32551): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
01-16 06:01:52.077 E/CrashHandler(32551): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
01-16 06:01:52.077 E/CrashHandler(32551): at dalvik.system.NativeStart.main(Native Method)
**01-16 06:01:52.077 E/CrashHandler(32551): Caused by: android.os.TransactionTooLargeException**
01-16 06:01:52.077 E/CrashHandler(32551): at android.os.BinderProxy.transact(Native Method)
01-16 06:01:52.077 E/CrashHandler(32551): at android.view.IWindowSession$Stub$Proxy.addToDisplay(IWindowSession.java:664)
01-16 06:01:52.077 E/CrashHandler(32551): at android.view.ViewRootImpl.setView(ViewRootImpl.java:534)
以及檔案不能打開的異常(Failed to open database ):
01-16 07:28:32.140 E/SQLiteDatabase( 5954): Failed to open database '/data/data/com.demo.test/databases/ua.db'.
01-16 07:28:32.140 E/SQLiteDatabase( 5954): android.database.sqlite.SQLiteCantOpenDatabaseException: unknown error (code 14): Could not open database
01-16 07:28:32.140 E/SQLiteDatabase( 5954): at android.database.sqlite.SQLiteConnection.nativeOpen(Native Method)
01-16 07:28:32.140 E/SQLiteDatabase( 5954): at android.database.sqlite.SQLiteConnection.open(SQLiteConnection.java:209)
這些異常都有可能是檔案打開過多引起的。
那怎麼知道檔案數量究竟打開了多少呢?系統的額度是多少呢?
下面就來看一下(也是遇到了問題,才曉得這樣看)
檢視系統對打開檔案數量的限制
首先進入adb shell環境:
#cat /proc/sys/fs/file-max
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsIyZuBnL3kzMyUTNwkTM2ETMwkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
輸出為86721,即整個系統限制數量。
檢視整個系統已經打開檔案數量
#cat /proc/sys/fs/file-nr
第一列就是整個系統一共打開的數量
檢視單個程序的打開檔案數量限制
#ulimit -n
由此可以看到限制是1024個。如果超出了就要抛異常了。
檢視單個程序打開了哪些檔案句柄
#ls -l /proc/26353/fd/ (26353為程序的程序id)
由上圖可以看到打開了哪些。
另外,也可以設定單個程序打開檔案的限制:
這裡設定為30。但是要root才能設定。(親自測試,設定這個後實際程序打開檔案數量大于這個數值,也還是沒有抛too many open files)。原因還不清楚。不知道是否麼有設定到核心中。)
ulimit -HSn 30
以上指令中,H指定了硬性大小,S指定了軟性大小,n表示設定單個程序最大的打開檔案句柄數量。最好不要超過4096,畢竟打開的檔案句柄數越多響應時間肯定會越慢。
怎麼會出現fd leadk洩漏?
1.檔案打開後未關閉。
2.流打開沒有關閉
3.大量socket連接配接打開沒有關閉。
4.管道、Context provider、資料庫沒有關閉, 或者資料庫連結頻繁打開忘記關閉。
是以,一定要優雅的寫代碼。