源码学习:文件描述符

news2024/11/24 11:04:45

在进程描述学习中,扯到了max_fds,接着就联想到了日常运维中常见的ulimit参数、sysctl内核参数,原来以为max_fds与这些个关联性比较强,但经过一早上折腾以后,发现其实还是有一些差距的。但是在学习过程中,却是东拉西扯折腾出了很多其他东西。

现在尝试把这些东西都统一消化一下。

文件描述符File Descriptor

fd 是 File descriptor 的缩写,中文名叫做:文件描述符。文件描述符是一个非负整数,本质上是一个索引值。

fd是索引值!fd是索引值!fd是索引值!

重要的事情说三遍。

什么时候需要fd

当打开一个文件时,内核向进程返回一个文件描述符( open 系统调用得到 ),后续 read、write 这个文件时,则只需要用这个文件描述符来标识该文件,将其作为参数传入 read、write 。

如同task_struct内的struct files_struct     *files

struct task_struct {
    // ...
    /* Open file information: */
    struct files_struct     *files;
    // ...
    }

此处的files 是一个指针,指向一个为 struct files_struct 的结构体。这个结构体就是用来管理该进程打开的所有文件的管理结构。

struct task_struct 是进程的抽象封装,标识一个进程。当创建一个进程,其实也就是 new 一个 struct task_struct 出来;

上面代码通过进程结构体引出了 struct files_struct 这个结构体。这个结构体管理某进程打开的所有文件的管理结构,核心代码如下:

struct files_struct {
....
    struct fdtable __rcu *fdt;
    struct fdtable fdtab;  //动态数组
....
    struct file __rcu * fd_array[NR_OPEN_DEFAULT]; //静态数组
....
};

files_struct 结构体是用来管理所有打开的文件的。通过数组进行管理,所有打开的文件结构都在数组里。struct files_struct内有两个数组,一个静态数组,一个动态数组。

由于大部分进程只会打开少量的文件,所以静态数组就够了,这样就不用另外分配内存。如果超过了静态数组的阈值,那么就动态扩展,使用动态数组。

静态数组

#define NR_OPEN_DEFAULT BITS_PER_LONG

这是一个静态数组,随着 files_struct 结构体分配出来的,在 64 位系统上,静态数组大小为 64;

定义代码如下,BITS_PER_LONG在64位系统上为64:

#define NR_OPEN_DEFAULT BITS_PER_LONG

动态数组

struct fdtable

这个是数组管理结构,封装用来管理 fd 的结构体,代码如下

struct fdtable {
    unsigned int max_fds;
    struct file __rcu **fd;      /* current fd array */
    unsigned long *close_on_exec;
    unsigned long *open_fds;
    unsigned long *full_fds_bits;
    struct rcu_head rcu;
};

fdtable.fd 这个字段是一个二级指针,指向 fdtable.fd 是一个指针字段,指向的内存地址还是存储指针的(元素指针类型为  struct file * )。换句话说,fdtable.fd 指向一个数组,数组元素为指针(指针类型为 struct file *)。其中 max_fds 指明数组边界。

file_struct 本质上是用来管理所有打开的文件的,内部的核心是由一个静态数组和动态数组管理结构实现。而文件描述符fd 就是这个数组的索引,也就是数组的槽位编号已。 通过非负数 fd 就能拿到对应的 struct file 结构体的地址。

日常运维与fd擦边的参数

1. file-max

/proc/sys/fs/file-max

这个文件决定了系统级别所有进程可以打开的文件描述符的数量限制,尝试分配超过file-max值的文件描述符将通过printk报告,查找包含"VFS: file-max limit reached"的信息。

root@linux-kernel:/# sysctl -a | grep -i file-max fs.file-max = 65535

修改方式

echo "fs.file-max = 65535000" >> /etc/sysctl.conf

sysctl -p

2. file-nr

这个是一个状态指示的文件,一共三个值,第一个代表全局已经分配的文件描述符数量,第二个代表自由的文件描述符(待重新分配的),第三个代表总的文件描述符的数量。

Linux 2.6 版本始终将空闲文件句柄数量报告为0 —— 这不是错误,而是表示已分配的文件句柄数量恰好等于已使用的文件句柄数量。

root@linux-kernel:/# cat /proc/sys/fs/file-nr

1248    0    9223372036854775807

3. nr_open

表示一个进程可以分配的最大文件句柄数量。默认值是1024*1024(1048576),对大多数机器来说应该足够了。实际限制取决于RLIMIT_NOFILE资源限制。

unsigned int sysctl_nr_open __read_mostly = 1024*1024;
unsigned int sysctl_nr_open_min = BITS_PER_LONG;

4. RLIMIT_NOFILE

RLIMIT_NOFILE是一个用于限制单个进程可以打开的文件描述符数量的资源限制。它定义了当前进程能够同时打开的最大文件描述符数量。这个限制是针对每个进程的,而不是系统整体的。通过调整这个限制,可以控制每个进程能够同时处理的文件数量,从而对系统的资源利用进行管理和优化。

可以通过ulimit -n 配置(重启后失效) 或者配置/etc/security/limits.conf永久生效。openEuler默认为1024

其中nofile为number of open file, 为打开文件数量,针对单个进程和用户。

# /etc/security/limits.conf //将可打开数量设置为65535 
* soft nofile 65535 
* hard nofile 65535

对应limit默认值配置源码如下,用户空间的NR_OPEN配置为1024.

另外可以通过程序接口 setrlimit()、getrlimit() 进行设置

int do_prlimit(struct task_struct *tsk, unsigned int resource,
        struct rlimit *new_rlim, struct rlimit *old_rlim)
{
    struct rlimit *rlim;
    int retval = 0;
    ...
    if (new_rlim) {
        if (new_rlim->rlim_cur > new_rlim->rlim_max)
            return -EINVAL;
        if (resource == RLIMIT_NOFILE &&
                new_rlim->rlim_max > sysctl_nr_open)
            return -EPERM;
    }
    ...
}

在/proc/sys/fs下三个参数的加载源码

static struct ctl_table fs_table[] = {
   ...
    {
        .procname   = "file-nr",
        .data       = &files_stat,
        .maxlen     = sizeof(files_stat),
        .mode       = 0444,
        .proc_handler   = proc_nr_files,
    },
    {
        .procname   = "file-max",
        .data       = &files_stat.max_files,
        .maxlen     = sizeof(files_stat.max_files),
        .mode       = 0644,
        .proc_handler   = proc_doulongvec_minmax,
        .extra1     = &zero_ul,
        .extra2     = &long_max,
    },
    {
        .procname   = "nr_open",
        .data       = &sysctl_nr_open,
        .maxlen     = sizeof(unsigned int),
        .mode       = 0644,
        .proc_handler   = proc_dointvec_minmax,
        .extra1     = &sysctl_nr_open_min,
        .extra2     = &sysctl_nr_open_max,
    }
    ...

nr_open、file-max与RLIMIT_NOFILE的对比

范围:

  • nr_open:单个进程的文件描述符最大值。
  • file-max:系统范围内所有进程的文件描述符总数。
  • RLIMIT_NOFILE:每个进程的文件描述符软限制和硬限制。

层级:

  • nr_open 和 RLIMIT_NOFILE 作用于进程级别,控制单个进程可以打开的文件数量。
  • file-max 作用于系统级别,控制整个系统可以打开的文件数量。

限制机制:

  • nr_open 提供了一个系统范围内的进程级硬限制。
  • RLIMIT_NOFILE 可以通过用户或管理员动态调整,灵活性较高。
  • file-max 确保系统不会超出总的文件描述符资源,避免资源枯竭。

关联性:

在 Linux 系统中,NR_OPEN 是一个内核中定义的常量,它表示整个系统可以同时打开的文件描述符的最大数量。一旦这个常量在内核中设置为某个值(比如1024),那么系统级别的文件描述符总数就会受到这个限制。

用户进程可以通过 RLIMIT_NOFILE 这个资源限制来控制其自身可以打开的文件描述符数量。这个限制是针对每个进程的,与 NR_OPEN 不同,它影响的是单个进程的能力,而不是整个系统。

如果 NR_OPEN 被设置为 1024,这意味着整个系统在任何时刻都不会超过 1024 个打开的文件描述符。但是,每个单独的进程可以通过 RLIMIT_NOFILE 设置自己的最大文件描述符数量。默认情况下,如果不显式设置,RLIMIT_NOFILE 的值通常会比较大,远超过 NR_OPEN 的设置,允许进程在其自身的限制内操作。

因此,即使 NR_OPEN 设置为 1024,用户进程仍然可以通过设置适当的 RLIMIT_NOFILE 来打开更多的文件描述符,只要它们不超过其自身的限制。这种设置允许操作系统在系统级别保持资源的控制,同时让每个进程有足够的灵活性来管理自己的资源使用。

在设置和检查文件描述符时,内核会结合这几个参数来确保资源使用在合理范围内。例如,当一个进程请求打开新的文件描述符时,内核会检查 RLIMIT_NOFILE 和 nr_open,同时在全局范围内检查是否超过 file-max。

通过这些参数的组合,Linux 内核能够灵活而有效地管理文件描述符资源,确保系统稳定和高效运行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1879687.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java基于ssm+jsp 固定资产管理系统

1前台首页功能模块 固定资产管理系统,在系统首页可以查看首页、设备信息、论坛信息、我的、跳转到后台等内容,如图1所示。 图1前台首页功能界面图 注册,在注册页面可以填写用户名、密码、姓名、性别、头像、身份证、手机等详细内容&#xff…

ASP.NET CORE应用针对IIS有哪两种部署模式?

一、ASP.NET CORE Core Module IIS其实也是按照管道的方式来处理请求的,但是IIS管道和ASP.NET CORE中间件管道有本质的不同。对于部署在IIS中的Web应用来说,从最初接收到请求到最终将响应发出去,这段处理流程被细分为一系列固定的步骤&#x…

设计模式-状态模式和策略模式

1.状态模式 1.1定义 当一个对象的内在状态改变时允许根据当前状态作出不同的行为; 1.2 适用场景 (1)一个对象的行为取决于它的状态,并且它必须在运行时根据状态来决定其行为. (2)代码中包含了大量的与状态有关的条件语句,例如:一个操作含有庞大的多分值语句(if…

【信息安全及等保】网络安全等级保护技术建议书(word原件)

1信息系统详细设计方案 1.1安全建设需求分析 1.1.1网络结构安全 1.1.2边界安全风险与需求分析 1.1.3运维风险需求分析 1.1.4关键服务器管理风险分析 1.1.5关键服务器用户操作管理风险分析 1.1.6数据库敏感数据运维风险分析 1.1.7“人机”运维操作行为风险综合分析 1.2…

3D打印随形水路在注塑生产中的显著优势

3D打印技术在模具制造中已崭露头角,特别是在注塑生产中,3D打印随形水路的应用正变得日益普遍。 首先,该技术能精准优化模具温度。3D打印随形水路随形冷却的设计让模具温度更加均匀,水路更贴近产品,有效提升产品品质和缩…

不知道自己的优势擅长和兴趣爱好,我该如何填报高考志愿选专业?

天生我才必有用,每个人都是独立的个体,拥有自己的优势和擅长,当然这个优势和擅长,不是和别人对比,而是和自己对比产生的。 如果说你不知道自己的优势擅长,不知道自己的兴趣和爱好,那只不过是你没…

李一桐遭遇蜈蚣惊魂

李一桐遭遇“蜈蚣惊魂”!刘宇宁展现真男人本色在娱乐圈的幕后,总有一些心跳加速的惊险。近日,李一桐在拍戏时遭遇了一场“蜈蚣惊魂”,让无数粉丝和网友为她捏了一把冷汗。而在这场惊险的遭遇中,刘宇宁展现出了真男人的…

[寄宿日记]韩漫日漫无删减完整版,免费在线观看漫画

[寄宿日记]韩漫日漫无删减完整版,免费在线观看漫画 不能多说,怕审-核不过,自己看图吧。 想要的在这里: https://blog.csdn.net/qq_42098517/article/details/140079915 https://gitee.com/zzwuweijun/manhua/blob/master/README…

【原理】机器学习中的最小二乘法公式推导过程

本文来自《老饼讲解-BP神经网络》https://www.bbbdata.com/ 目录 一、什么是最小二乘法1.1. 什么是最小二乘法1.2. 最小二乘法的求解公式 二、最小二乘法求解公式的推导 最小二乘法是基本的线性求解问题之一,本文介绍最小二乘法的原理,和最小二法求解公式…

【PyTorch单点知识】神经元网络模型剪枝prune模块介绍(上,非结构化剪枝)

文章目录 0. 前言1. 剪枝prune主要功能分类2. torch.nn.utils.prune中的方法介绍3. PyTorch实例3.1 BasePruningMethod3.2PruningContainer3.3 identity3.4random_unstructured3.5l1_unstructured 4. 总结 0. 前言 按照国际惯例,首先声明:本文只是我自己…

接口请求网关超时排查和引发的思考

问题描述 前端请求服务端接口,返回504 Gateway Timeout,请求接口为https://profile.noodles.com/user-mail-pub/api/user-mail/user-trash-mails?userId123456 原因分析 观察日志,发现网关链接超时,并且对应请求没有达到对应服…

四川省高等职业学校大数据技术专业建设暨专业质量监测研讨活动顺利开展

6月21日,省教育评估院在四川邮电职业技术学院组织开展全省高等职业学校大数据技术专业建设暨专业质量监测研讨活动。省教育评估院副院长赖长春,四川邮电职业技术学院党委副书记、校长冯远洪,四川邮电职业技术学院党委委员、副校长程德杰等出席…

【python】python知名品牌调查问卷数据分析可视化(源码+调查数据表)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

抓紧收藏!7 款令人惊艳的 AI 开源项目

🐼 关注我, 了解更多 AI 前沿资讯和玩法,AI 学习之旅上,我与您一同成长! 🎈 进入公众号,回复 AI, 可免费领取超多实用的 AI 资料 和内容丰富的 AI 知识库地址。 自从去年 AIGC 兴起以来,AI 开源…

gin 服务端无法使用sse流式nginx配置

我在本地使用 gin 可以流式的将大模型数据传递给前端。但是当我部署到服务器中时,会阻塞一段时间,然后显示一大段文本。 起初我怀疑是gin 没有及时将数据刷到管道中,但是经过测试,还是会阻塞。 c.Writer.(http.Flusher).Flush()最…

使用LabVIEW报告生成工具包时报错97

问题详情: 在运行使用Excel/Word调用节点的程序时,收到错误97:LabVIEW:(十六进制0x61)输入中传递了一个空引用句柄或先前已删除的引用句柄。 当运行报告生成工具包中的一个示例程序时,收到错误…

【python】python入门day2——数据类型与运算

python数据类型与运算 一、Python中变量的数据类型1、数据类型分类2、数值类型3、布尔类型4、字符串类型5、其他类型(了解) 二、Python数据类型转换1、使用Python实现超市的收银系统2、Python数据类型的转换方法3、总结 三、Python运算符1、算术运算符3、赋值运算符4、复合赋值…

计算机科学基础简单介绍(1—6)

计算机影响了我们生活的方方面面,在我们这个时代完全渗透了我们的生活。 最早是算盘、星盘、时钟、尺卡等古老的计算工具,后来出现了进步计算机,类似与汽车里程表的一种机械工具,但是他也是手工制品。经过历史的演变与发展&#x…

Prompting已死?DSPy:自动优化LLM流水线

在 LLM 应用中,如何优化一个 pipeline 的流程一直是一个比较头疼的问题。提示词作为一个预定义字符串,往往也没有很好地优化方向。本文中的 DSPy 框架或许能在实际应用中对效果优化起到一定帮助。 当前,在 LLM 的应用中,大家都在探…

LSTM时间序列基础学习

时间序列 时间序列可以是一维,二维,三维甚至更高维度的数据,在深度学习的世界中常见的是三维时间序列,这三个维度分别是(batch_size,time_step,input_dimensions)。 其中time_step是时间步,它…