源码学习:文件描述符

在进程描述学习中,扯到了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.mzph.cn/news/863103.shtml

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

相关文章

【C++】数组、字符串

六、数组、字符串 讨论数组离不开指针,指针基本上就是数组的一切的基础,数组和指针的相关内容参考我的C系列博文:【C语言学习笔记】四、指针_通过变量名访问内存单元中的数据缺点-CSDN博客【C语言学习笔记】三、数组-CSDN博客 1、数组就是&…

数据结构03 链表的基本操作【C++数组模拟实现】

前言:本节内容主要了解链表的基本概念及特点,以及能够通过数组模拟学会链表的几种基本操作,下一节我们将通过STL模板完成链表操作,可以通过专栏进入查看下一节哦~ 目录 单链表及其特点 完整链表构成 完整链表简述 创建单链表 …

京东云备案流程图_云主机快速ICP备案_京东云服务器备案问题解答

京东云ICP备案流程,备案包括网站和APP备案,以及备案问题解答FAQ,阿腾云以京东云网站域名备案流程为例,先填写主办单位信息,选择网站备案或APP备案,申请授权码并验证,填写并上传主办单位详细信息…

光伏仿真软件是什么?都有哪些功能?

光伏仿真软件,作为现代光伏系统设计的重要工具,正日益受到设计师、工程师和决策者的青睐。它结合了物理学、工程学和计算机科学的原理,以数字化方式模拟光伏系统的运行,帮助用户预测和优化系统的性能。本文将详细探讨光伏仿真软件…

[Go 微服务] go-micro + consul 的使用

文章目录 1.go-micro 介绍2.go-micro 的主要功能3.go-micro 安装4.go-micro 的使用4.1 创建服务端4.2 配置服务端 consul4.3 生成客户端 5.goodsinfo 服务5.1 服务端开发5.2 客户端开发 1.go-micro 介绍 Go Micro是一个简化分布式开发 的微服务生态系统,该系统为开…

Java学习【IO流:深入理解与应用(上)】

Java学习【IO流:深入理解与应用(上)】 🍃1.IO流体系结构🍃2.FileOutputStream🍁2.1FileOutputStream写数据的三种方式🍁2.2换行和续写 🍃3.FileInputStream🍁3.1每次读取…

软考高项备考经验分享

高项备考经验分享 在备考被论文卡两次后,这次终于通过了高项,分不是很高,比较幸运,对这次考试做个总结与分享,希望对同学们有所帮助。 1、备考时间 首先备考时间上不建议拉的太长,每天坚持看书3~6个月时…

《编译原理》阅读笔记:p25-p32

《编译原理》学习第 5 天,p25-p32总结,总计 8 页。 一、技术总结 1.lexical lexical这个单词后续会经常用到,所以首先要搞懂它的英文意思,不然看到中文的“词法,语法,文法”这三个词的时候就会懵了——l…

Java实现 现场评委给参赛选手打分的过程

通过评委的积极参与和公正评分,可以提高评选活动的公信力和可信度。 透明性:参赛者和观众应该清楚了解评审标准和评分过程,以便能够理解评委的评判依据。 可靠性:评委评分应该具有一致性和可靠性,不受主观因素或随机误差的影响。 编写程序,Java代码实现&#xff1…

计算机组成原理:海明校验

在上图中,对绿色的7比特数据进行海明校验,需要添加紫色的4比特校验位,总共是蓝色的11比特。紫色的校验位pi分布于蓝色的hi的1, 2, 4, 8, 16, 32, 64位,是2i-1位。绿色的数据位bi分布于剩下的位。 在下图中,b1位于h3&a…

浅谈安科瑞ACRELCLOUD-1200光伏发电系统在建筑节能中的应用

摘要:21世纪以来,随着不可再生能源的逐渐减少,人们越来越重视能源的利用率,不断开发绿色能源。通过光伏发电系统,能够提升能源利用率,减少不可再生能源的开发。同时,也能加强我国建筑节能系统的…

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

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

每日一道算法题 面试题 08.08. 有重复字符串的排列组合

题目 面试题 08.08. 有重复字符串的排列组合 - 力扣(LeetCode) Python class Solution:def permutation(self, S: str) -> List[str]:# 以索引记录字符是否用过lelen(S)idx[_ for _ in range(le) ]# 组合得到的字符串combine[]*leans[]# 递归def fu…

Go 中使用map时注意的问题

💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

面对资质申请被拒,河南企业如何调整策略再次冲刺?

当乙级风力发电资质申请未通过时,不必过于焦虑,以下是一份详细的二次申请攻略,帮助你更有条理地准备和提交申请: 一、失败原因分析与总结 查询评审意见:在收到评审结果后,首先查询并仔细阅读专家评审意见&…

利用python爬取上证指数股吧评论并保存到mongodb数据库

大家好,我是带我去滑雪! 东方财富网是中国领先的金融服务网站之一,以提供全面的金融市场数据、资讯和交易工具而闻名。其受欢迎的“股吧”论坛特别适合爬取股票评论,东方财富网的股吧聚集了大量投资者和金融分析师,他们…

vue开发网站--关于window.print()调取打印

1.vue点击按钮调取打印 点击按钮&#xff1a; 调取打印该页面&#xff1a; <div click"clickDown()">下载</div>methods: {//下载-调取打印clickDown() {window.print()}, }<style>/* 点击打印的样式 */media print {.clickDown {display: no…

推荐一款免费的GIF编辑器——【ScreenToGif编辑器】

读者大大们好呀&#xff01;&#xff01;!☀️☀️☀️ &#x1f440;期待大大的关注哦❗️❗️❗️ &#x1f680;欢迎收看我的主页文章➡️木道寻的主页 文章目录 &#x1f525;前言&#x1f680;素材准备&#x1f680;逐帧制作&#x1f680;保存图片⭐️⭐️⭐️总结 &#…

【吊打面试官系列-MyBatis面试题】MyBatis 框架适用场合?

大家好&#xff0c;我是锋哥。今天分享关于 【MyBatis 框架适用场合 &#xff1f;】面试题&#xff0c;希望对大家有帮助&#xff1b; MyBatis 框架适用场合&#xff1f; 1、MyBatis 专注于 SQL 本身&#xff0c;是一个足够灵活的 DAO 层解决方案。 2、对性能的要求很高&#…

Java | Leetcode Java题解之第191题位1的个数

题目&#xff1a; 题解&#xff1a; public class Solution {public int hammingWeight(int n) {int ret 0;while (n ! 0) {n & n - 1;ret;}return ret;} }