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
输出为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、数据库没有关闭, 或者数据库链接频繁打开忘记关闭。
所以,一定要优雅的写代码。