之前在公司写过一个生产工具,通过读写某个驱动节点实现设备信息更改的功能,结果测试拷机两小时必挂,一看内核打印“打开文件失败”,perror了之后打开文件太多了,这时候我就猜到是fd(文件描述符)泄露了。fd泄露是怎么回事呢,linux打开文件通常都是open返回一个fd的形式,操作系统会维护当前进程打开文件的记录,但是数量是被限制的,操作系统能打开的fd总和也是有限的,如果进程一直打开文件而不关闭,那么当调用open时操作系统将会返回失败。所以特别实在服务型进程和常驻内存的进程中,打开了文件就要记得在不用时关闭,否则只打开不关闭将会泄露句柄。当然进程结束,操作系统会自己关闭回收fd的,所以如果进程执行时间短就结束了,打开fd少,理论上也可以不显式关闭,但是调用close还是一种良好的习惯。
/proc/pid/fd
/proc/pid/fd文件夹是Linux挂载的记录当前打开文件描述符(fd)信息的,每打开一个fd就会有一个以fd为文件名的文件产生:
oujiangping at ubuntu in ~/project/test
$ sudo ls /proc/3645/fd
0 1 10 11 12 2 3 4 5 6 7 8 9
定位
如果你ls发现fd数量特别多,那就要考虑一下是否fd泄露了。用lsof可以看到详细的情况:
nm-applet 3645 oujiangping 0r CHR 1,3 0t0 6 /dev/null
nm-applet 3645 oujiangping 1u CHR 136,2 0t0 5 /dev/pts/2
nm-applet 3645 oujiangping 2u CHR 136,2 0t0 5 /dev/pts/2
nm-applet 3645 oujiangping 3r CHR 1,9 0t0 11 /dev/urandom
nm-applet 3645 oujiangping 4u unix 0x0000000000000000 0t0 30080 type=STREAM
nm-applet 3645 oujiangping 5u a_inode 0,11 0 9114 [eventfd]
nm-applet 3645 oujiangping 6u unix 0x0000000000000000 0t0 30082 type=STREAM
nm-applet 3645 oujiangping 7u a_inode 0,11 0 9114 [eventfd]
nm-applet 3645 oujiangping 8u unix 0x0000000000000000 0t0 30083 type=STREAM
nm-applet 3645 oujiangping 9u a_inode 0,11 0 9114 [eventfd]
nm-applet 3645 oujiangping 10u a_inode 0,11 0 9114 [eventfd]
nm-applet 3645 oujiangping 11u a_inode 0,11 0 9114 [eventfd]
nm-applet 3645 oujiangping 12u unix 0x0000000000000000 0t0 30085 type=STREAM