文件句柄
在文件I/O中,要从一个文件读取数据,应用程序首先要调用操作系统函数并传送文件名,并选一个到该文件的路径来打开文件。该函数取回一个顺序号,即文件句柄(file handle),该文件句柄对于打开的文件是唯一的识别依据。要从文件中读取一块数据,应用程序需要调用函数readFile,并将文件句柄在内存中的地址和要拷贝的字节数传送给操作系统。当完成任务后,再通过调用系统函数来关闭该文件。
文件句柄和文件描述符
文件句柄是windows里面的叫法,文件描述符是linux里面的叫法。其实两者是同样的概念。
最大文件句柄数
Linux 进程最多能够打开的文件句柄数(这里的文件句柄数包括socket数,从网络读取数据也是另外一种文件读取方式)是有限制的,超过了这个限制,应用程序就会抛出异常(Too many open files.)。在Android 上,最大的数量一般都是1024,但一些定制的rom可能会有一些差别。另外,有一个概念需要先明确,文件句柄数,并不是打开的文件数。因为一个文件即使被打开,也可能没有文件描述符。
获取文件句柄数
那么遇到问题的时候,如何获取某个进程的文件句柄数呢?
- 获取进程对应的ID:
adb shell ps | grep '进程名'
- 进入到对应的目录:
cd /proc/进程ID/fd
- 使用下面的命令即可能够获取到对应进程的文件句柄数:
ls /proc/进程ID/fd -l
- 如想要获取当前进程socket占用的文件句柄数,可以增加多个过滤:
ls /proc/进程ID/fd -l | grep socket -c
文件句柄泄漏定位
通常的分析手法如下(转自:https://blog.csdn.net/xiaolli/article/details/56012228):
(1). 确定是哪类文件打开太多,没有关闭.
- fd leaks, 通常伴随着此进程会出现Java Exception, Native Exception 等. 在mtk 的AEE DB 中, 有一支文件 PROCESS_FILE_STATE 描述, 此进程的打开的所有文件.
查看此文件, 确定哪个或者哪种文件打开数量最多,即追查此类文件打开如此多, 而没有被关闭的原因.
- 如果没有DB, 当发生文件句柄泄露到1024 时, 在L 版本后, 在Kernel Log 中search “FDLEAK”, 在L 版本之前, 在Kernel Log 中search “FS_TAG”, 即可枚举出所有的此进程所打开的文件.
- 如果问题容易复现,可以直接 adb shell ls -a -l /proc/pid/fd , 直接打印出当前此process 所有打开的文件.
(2). 确定此类文件是在哪里打开.
对于一些确定的文件, 比如/data/data/xxxx_app/yyyy 之类的文件, 通常开发者自己可以快速的确定打开文件的位置,基本上不需要debug,对于一些另外一些常见的场景说明如下:
- 大批量的打开“anon_inode:[eventpoll]” 和 “pipe”, 超过100个eventpoll, 通常情况下是开启了太多的HandlerThread/Looper/MessageQueue, 线程忘记关闭, 或者looper 没有释放. 可以抓取hprof 进行快速分析. 抓取hprof 可以参考FAQ:http://online.mediatek.com/Pages/FAQ.aspx?List=SW&FAQID=FAQ08893
- 对于system server, 如果有大批量的socket 打开, 可能是因为Input Channel 没有关闭, 此类同样抓取hprof, 查看system server 中WindowState 的情况.
- 大批量的打开“/dev/ashmem”, 如果是Context provider, 或者其他app, 很可能是打开数据库没有关闭, 或者数据库链接频繁打开忘记关闭.
(3). 暴力确定文件打开的位置
- MTK 有开发了fd leaks debug 功能,可以记录每次打开fd 的backtrace, 可以参考FAQ: http://online.mediatek.com/Pages/FAQ.aspx?List=SW&FAQID=FAQ11422
(4). 修正
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/180908.html原文链接:https://javaforall.cn