Linux 最大文件描述符数

最大文件描述符数量

文件描述符是服务器程序的宝贵资源,几乎所有系统调用都是和文件描述符打交道。而系统分配给进程的文件描述符数量有限,因此需要及时关闭那些不用的文件描述符。

Linux对应用程序能打开的最大文件描述符数量,有2个层次限制:用户级限制,系统级限制。
1)用户级限制,是指目标用户运行的所有进程总能打开的文件描述符数量;
2)系统级限制,是指所有用户总共能打开的文件描述符数量。

如何查看用户级文件描述符数限制?

可以使用ulimit命令查看

$ ulimit -n
1024

也可以通过ulimit命令设置用户级文件描述符数限制为max-file-number,不过这种修改是临时性的。

$ ulimit -SHn max-file-number

例如,max-file-number设置为2048

$ ulimit -SHn 2048
$ ulimit -n
2048

如果想要永久修改用户级文件描述符限制,可以在/etc/security/limits.conf文件中加入以下两项:

hard nofile max-file-number
soft nofile max-file-number

第一行是系统的硬限制,第二行是软限制。

如何修改系统级文件描述符数限制?

可以使用sysctl命令修改,不过也是临时性的

$ sysctl -w fs.file-max=max-file-number

如果要永久性修改系统级文件描述符数量限制,则需要在/etc/sysctl.conf 文件中添加这一项:

fs.file-max=max-file-number

然后,执行$ sysctl -p 命令,使更改生效。

如何在C程序中,获取用户级文件描述符数限制?

有两种方式:
1)sysconf 获取 _SC_OPEN_MAX;
2)getrlimit 获取 RLIMIT_NOFILE

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <errno.h>

int main()
{
    // 方式一: sysconf 获取 _SC_OPEN_MAX
    long openMax = sysconf(_SC_OPEN_MAX);
    if (openMax == -1) {
        perror("sysconf OPEN_MAX error");
        return -1;
    }
    printf("openMax = %ld\n", openMax);

    // 方式二: getrlimit 获取 RLIMIT_NOFILE
    struct rlimit limit;
    if (getrlimit(RLIMIT_NOFILE, &limit) == -1) {
        perror("getrlimit RLIMIT_NOFILE error");
        return -1;
    }
    printf("soft limit = %ld, hard limit = %ld\n", limit.rlim_cur, limit.rlim_max);
    return 0;
}

运行结果:

$ ./file_max_test
openMax = 1024
soft limit = 1024, hard limit = 4096

相对的,设置用户级文件描述符数限制,可以用setrlimit。注意,

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>
#include <errno.h>

int printOpenMax()
{
    // 方式一: sysconf 获取 _SC_OPEN_MAX
    long openMax = sysconf(_SC_OPEN_MAX);
    if (openMax == -1) {
        perror("sysconf OPEN_MAX error");
        return -1;
    }
    printf("openMax = %ld\n", openMax);

    // 方式二: getrlimit 获取 RLIMIT_NOFILE
    struct rlimit limit;
    if (getrlimit(RLIMIT_NOFILE, &limit) == -1) {
        perror("getrlimit RLIMIT_NOFILE error");
        return -1;
    }
    printf("soft limit = %ld, hard limit = %ld\n", limit.rlim_cur, limit.rlim_max);
    return 0;
}

int main()
{
    printOpenMax();

    // setrlimit 修改系统限制RLIMIT_NOFILE (用户级文件描述符数限制)
    struct rlimit limit;
    limit.rlim_cur = 2048;
    limit.rlim_max = 4096; // 注意不要大于 前面已经读取出来的rlim_max (4096)
    int ret = setrlimit(RLIMIT_NOFILE, &limit);
    if (ret == -1) {
        perror("setrlimit error");
        return -1;
    }

    printOpenMax();
    return 0;
}

如何查找文件(描述符)资源泄漏?

如果常驻进程(不会立即关闭的进程),由于忘记关闭文件,如何快速找到原因?

比如下面的程序:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    int cnt = 0;
    while (1) {
        char name[64];
        snprintf(name, sizeof(name), "%d.txt", cnt);
        int fd = creat(name, 0644);

        sleep(10);
        ++cnt;
    }
    return 0;
}

可以使用lsof工具,查看文件描述符相关信息。如:

$ ./open_file_test & # 后台运行上面的程序
[1] 24094

$ lsof -p 24094 # 显示指定进程(pid = 24094)打开的所有文件描述符

$ lsof -p 24094
COMMAND     PID   USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
open_test 24094 martin  cwd    DIR    8,1     4096 1728707 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin
open_test 24094 martin  rtd    DIR    8,1     4096       2 /
open_test 24094 martin  txt    REG    8,1    10417 1724410 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/open_test
open_test 24094 martin  mem    REG    8,1  1857312 2101633 /lib/x86_64-linux-gnu/libc-2.19.so
open_test 24094 martin  mem    REG    8,1   149120 2101617 /lib/x86_64-linux-gnu/ld-2.19.so
open_test 24094 martin    0u   CHR 136,15      0t0      18 /dev/pts/15
open_test 24094 martin    1u   CHR 136,15      0t0      18 /dev/pts/15
open_test 24094 martin    2u   CHR 136,15      0t0      18 /dev/pts/15
open_test 24094 martin    3w   REG    8,1        0 1724300 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/0.txt
open_test 24094 martin    4w   REG    8,1        0 1724324 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/1.txt
open_test 24094 martin    5w   REG    8,1        0 1724332 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/2.txt
open_test 24094 martin    6w   REG    8,1        0 1724333 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/3.txt
open_test 24094 martin    7w   REG    8,1        0 1724334 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/4.txt
open_test 24094 martin    8w   REG    8,1        0 1724337 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/5.txt
open_test 24094 martin    9w   REG    8,1        0 1724338 /home/martin/workspace/CLionProjects/c++/eftp/cmake-build-debug/bin/6.txt

可以清楚看到进程open_file_test (pid = 24094)打开了哪些文件,而没有被关闭。

参考

《Linux高性能服务器编程》
https://blog.csdn.net/CMbug/article/details/48313107

posted @ 2022-05-01 20:41  明明1109  阅读(1932)  评论(0编辑  收藏  举报