文件句柄和文件句柄泄漏解决

文件句柄

在文件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). 修正

<think>嗯,用户想了解文件句柄文件名称之间的区别。首先,我需要回忆一下相关的知识。根据之前提供的引用,文件句柄在Windows里叫法,而文件描述符是Linux的术语,但它们是类似的概念。文件名称就是文件文件系统中的路径,比如“/home/user/file.txt”。而文件句柄更像是操作系统用来管理打开文件的一个标识符。 用户可能混淆了这两者的概念,所以需要明确区分。文件名称是用户可见的路径,用于定位文件;而文件句柄是系统内部用来跟踪已打开文件的结构。比如,当程序打开一个文件时,系统会生成一个句柄,程序通过这个句柄进行读写操作,而不是直接使用文件名。 还要考虑不同操作系统下的情况,比如WindowsLinux。引用中提到,Windows有一些保留的文件名,比如CON、PRN等,这些不能用作文件名,否则会导致错误。这可能与句柄无关,但用户可能想知道文件名限制是否与句柄有关,需要指出它们的独立性。 另外,文件描述符在Linux中是数字,而文件句柄在Windows中可能是一个结构体或指针。需要解释它们的抽象层次不同:文件名是用户层的,句柄是系统层的资源标识符。 可能用户遇到的问题是,比如程序报错“too many open files”,这时候是因为文件句柄泄漏,没有正确关闭,导致超出系统限制。这时候需要调整最大文件句柄数,如引用4中的设置方法。但用户的问题主要是区别,所以需要先明确概念,再提到相关问题。 总结下来,回答的结构应该先定义两者,然后分点比较它们的区别,比如功能、生命周期、系统限制、使用场景等。再举例子说明,比如打开文件时的流程,以及错误情况的处理。最后,生成相关问题,帮助用户深入理解。</think>### 文件句柄 vs 文件名称 区别解释 #### 1. **定义差异** - **文件名称**:是文件文件系统中的唯一标识符,以路径形式表示(例如:`/home/user/test.txt` 或 `C:\data\file.doc`),用于定位文件在存储设备中的具体位置[^1]。 - **文件句柄**:是操作系统内核为进程分配的资源标识符,用于跟踪管理已打开的文件。在Linux中称为文件描述符(如数字`3`),在Windows中表现为句柄对象(如`HANDLE`类型)[^2][^3]。 #### 2. **功能对比** - **文件名称**: - 用户可见,用于读写、删除等操作。 - 可被多个进程同时引用(如多个程序读取同一文件)。 - **文件句柄**: - 用户不可见,仅在程序运行时通过系统调用(如`open()`)生成。 - 代表进程与文件之间的**活动连接**,包含读写位置、访问模式等信息[^3]。 #### 3. **生命周期** - **文件名称**: - 永久存在,除非文件被删除或重命名。 - **文件句柄**: - 临时存在,随文件打开而创建,关闭时释放。 - 未正确释放会导致**文件句柄泄漏**,引发`too many open files`错误[^2][^4]。 #### 4. **系统限制** - **文件名称**: - 受文件系统命名规则限制(例如Windows禁止使用`CON`、`LPT1`等保留名称[^5])。 - **文件句柄**: - 受操作系统全局或进程级限制(例如Linux默认每个进程最多打开1024个文件描述符,可通过`ulimit -n`调整[^4])。 #### 5. **使用场景示例 ```python # 打开文件时,文件名转换为句柄 file = open("data.txt", "r") # "data.txt"是文件名,file是句柄对象 content = file.read() # 通过句柄操作文件 file.close() # 释放句柄 ``` 若未执行`close()`,即使删除文件名,文件数据仍占用磁盘空间,直到所有关联句柄关闭。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值