源码学习:文件描述符

在进程描述学习中,扯到了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.mfbz.cn/a/756360.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Al+医学,用这个中文多模态医学大模型帮你看胸片

随着人工智能技术的飞速发展,AI 在医学领域的应用已经成为现实。特别是在医学影像诊断方面,AI 大模型技术展现出了巨大的潜力和价值,但目前针对中文领域医学大多模态大模型还较少。 今天马建仓为大家介绍的这款 XrayGLM,就是由澳…

Redis-实战篇-缓存更新策略(内存淘汰、超时剔除、主动更新)

文章目录 1、缓存更新策略1.1、内存淘汰1.2、超时剔除1.3、主动更新 2、业务场景:3、主动更新在企业中业务实现有三种方式3.1、Cache Aside Pattern3.1.1、操作缓存和数据库时有三个问题需要考虑:3.1.1.1、删除缓存还是更新缓存?3.1.1.2、如何…

大模型应用-多模态和大模型是如何相互成就的

前言 如果单纯的将大模型用来聊天,那就是low了。 而多模态赋予了大模型更多的现实价值,大模型则助力多模态变得更强大。 多模态 我们所处的是一个物理世界,不同事物之间模态多种多样,即便是简单的文本,按照语言&am…

FreeRTOS的裁剪与移植

文章目录 1 FreeRTOS裁剪与移植1.1 FreeRTOS基础1.1.1 RTOS与GPOS1.1.2 堆与栈1.1.3 FreeRTOS核心文件1.1.4 FreeRTOS语法 1.2 FreeRTOS移植和裁剪 1 FreeRTOS裁剪与移植 1.1 FreeRTOS基础 1.1.1 RTOS与GPOS ​ 实时操作系统(RTOS):是指当…

java基于ssm+jsp 二手车交易网站

1用户功能模块 定金支付管理,在定金支付管理页面可以填写订单编号、车型、品牌、分类、车身颜色、售价、订金金额、付款日期、备注、用户名、姓名、联系方式、是否支付等信息,进行详情、修改,如图1所示。 图1定金支付管理界面图 预约到店管…

计算Dice损失的函数

计算Dice损失的函数 def Dice_loss(inputs, target, beta1, smooth 1e-5):n,c, h, w inputs.size() #nt,ht, wt, ct target.size() #nt,if h ! ht and w ! wt:inputs F.interpolate(inputs, size(ht, wt), mode"bilinear", align_cornersTrue)temp_inputs t…

wsl2收缩虚拟磁盘,减少空间占用

一、说明 由于WSL2使用的是虚拟磁盘,当虚拟磁盘的空间变大时,仅仅删除WSL2文件系统中没有用到的大文件,磁盘空间是无法自动收缩回收的。本文介绍了一种回收WSL2虚拟磁盘空间的方法。 二、停止WSL2 在收缩 WSL2 虚拟磁盘之前,需…

《概率论与数理统计》期末复习笔记_上

目录 第1章 随机事件与概率 1.1 随机事件 1.2 事件的关系与运算 1.3 概率的定义与性质 1.4 古典概型_重点 1.5 几何概型 1.6 条件概率与乘法公式 1.7 全概率公式与贝叶斯公式_重点 1.8 事件的独立性_重点 1.9 伯努利概型_重难点 第2章 随机变量及其分布 2.1 随机变…

​​Linux(CentOS)​​同步服务器时间之~​​chrony​​

Chrony 是一款开源的网络时间协议(NTP)客户端和服务端软件,旨在提供高精度的时间同步功能。相较于传统的 NTP 实现如 ntpd,Chrony 提供了一些改进和优势,包括更快的同步速度、低延迟、低CPU占用和低内存消耗。以下是 Chrony 的几个关键特性和…

华润万家超市卡怎么用?

华润的礼品卡不仅能线下门店使用,还能直接叫送货上门 我最近用积分兑了几张华润卡,但是又没有购物需求,送朋友吧面值又不大,朋友也说用不上 最后朋友建议我在收卡云上把卡出掉,我试了下92折出掉了,价格还…

面对全球新能源汽车合作发展创维汽车如何实现共赢

由全球新能源汽车合作组织(筹)主办、中国电动汽车百人会承办的首届全球新能源汽车合作发展论坛(GNEV2024)于6月27日,6月28日在新加坡金沙会议展览中心召开。创维汽车国际营销公司总经理齐奎源受邀参会并作出分享。 本届大会以推动全球新能源汽车产业协同发展与合作…

GenAI 用于客户支持 — 第 1 部分:构建我们的概念验证

作者:来自 Elastic Chris Blaisure 欢迎来到 Inside Elastic 博客系列,我们将展示 Elastic 的内部运营如何解决实际业务挑战。本系列将揭示我们将生成式 AI(gererative AI - GenAI)集成到客户成功和支持运营中的历程,让…

【Mac】Listen 1 for Mac(最强的音乐搜索工具)软件介绍

软件介绍 Listen 1 for Mac 是一款非常方便的音乐播放软件,主要功能是集成多个音乐平台,让用户可以方便地搜索、播放和管理音乐。它是一个用 Python 语言开发的免费开源综合音乐搜索工具项目,最大的亮点在于可以搜索和播放来自网易云音乐&am…

JAVA医院绩效考核系统源码:三级公立医院绩效考核系统源码 可源码交付,支持二开

JAVA医院绩效考核系统源码:三级公立医院绩效考核系统源码 可源码交付,支持二开 医院绩效考核系统是一个集数据采集、分析、评估、反馈于一体的信息化工具,旨在提高医疗服务质量、优化资源配置、促进医院可持续发展。以下是对医院绩效考核系统…

【React】第二个组件的一点小问题(JSX元素需要被包裹)

能看出为什么报错吗? 它告诉我们JSX元素需要被包裹,此时只需在所有元素外套一层标签(空标签也可以哦) 专业点就是要有一个根元素 注释: ctrl / 效果是 {/* */}这样 三元运算符:同CPP 循环输出数组&#x…

Firefox 编译指南2024 Windows10篇- 源码获取(二)

1. 引言 在成功准备了编译环境之后,下一步就是获取Firefox的源码。源码是编译任何软件的基础,对于开源项目如Firefox尤其重要。通过获取并理解源码,开发者不仅能够编译出自定义版本的Firefox,还能对其进行修改和优化,…

html纯原生网页引入vue3版本的quill editor

效果图 版本 vueup/vue-quill v1.2.0vue3.3.8Element Plus v2.4.2 引入流程 找一个vue3的项目, 然后安装插件vue版本的quill: vue-quill npm install vueup/vue-quill --save官方地址:https://vueup.github.io/vue-quill/ 安装完成之后,把vue-quil插件下…

C++中的数据结构

一.STL标准库 结构:STL中有六大组件,分别是:容器,算法,迭代器,仿函数,配接器,配置器;以下分别介绍这六大组件中的最主要的三个。 1.容器 容器来配置存储空间,算法通过…

CSS的 text-decoration

text-decoration text-decoration CSS 简写属性设置文本上的装饰性线条的外观。它是 text-decoration-line、text-decoration-color、text-decoration-style 和较新的 text-decoration-thickness 属性的缩写。 MDN text-decoration text-decoration 可以设置1到4个参数, 允许…