• 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

  • 相关阅读:
    为什么Java不支持多重继承
    thymeleaf生成页面时报错:An error happened during template parsing (template: "class path resource [templates/index.html]")的解决办法
    MySQL操作数据时区分大小写
    java.lang.NoClassDefFoundError: com/jhlabs/image/RippleFilter
    多线程学习系列:(六)线程池基础下
    多线程学习系列:(四)线程同步基础下
    多线程学习系列:(八)Winform中多线程编程基础上
    多线程学习系列:(五)线程池基础上
    多线程学习系列:(七)基于多线程的基本组件
    HTTP头部
  • 原文地址:https://www.cnblogs.com/fortunely/p/16213956.html
Copyright © 2020-2023  润新知