news 2026/6/10 3:46:19

文件描述符(File Descriptors, 简称 FD)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
文件描述符(File Descriptors, 简称 FD)

文章目录

  • 文件描述符(file descriptor,简称 fd)本质上就是:操作系统给“已打开资源”分配的一个编号。非负整数
    • 分配编号后,后续操作就是围绕这个编号来的。代码通常不直接用 fd 编号;真正直接使用 fd 编号的是底层系统调用和操作系统内核
    • 进程启动后默认会有3个文件描述符
    • 只有当代码需要操作系统帮你“打开某种外部资源”时,才会分配fd,才会占用文件描述符。
      • 不是所有情况都是一个操作占一个fd
    • 每个进程都有自己的一张“文件描述符表”,这张表里面记录:fd 号码 -> 这个 fd 指向什么资源。文件描述符不是全局唯一的,而是进程内部的编号。
      • 为什么说fd是进程才有?文件描述符是操作系统为了管理某个进程打开的资源而分配的编号
      • 子进程会继承父进程的一些 fd
      • 父子进程的 fd 表不是同一张表,父进程和子进程都有自己的 fd 表
      • 线程有没有文件描述符?线程属于同一个进程,所以同一个进程内的多个线程共享同一张 fd 表。
    • 一切皆文件。Linux 把很多资源统一成“可以 open/read/write/close 的对象”。
      • 操作 fd,就是操作 fd 指向的资源
  • 单进程允许打开的最大文件描述符数量的限制。cat /proc/PID/limits | grep "open files"
    • 硬限制本身也是进程的属性。进程启动时,通常从父进程继承 soft limit 和 hard limit。
    • ulimit -n 当前 shell 以及由这个 shell 启动的子进程默认会继承的 fd 限制
    • 如何修改soft limit
  • 看某个进程当前打开的fd总个数。ls /proc/<PID>/fd | wc -l
  • 查看进程具体打开了哪些资源 lsof(list open files) -p <PID>。ls -l /proc/进程PID/fd
  • 进程当前打开的 fd 都指向哪些资源,并找出重复最多的资源

文件描述符(file descriptor,简称 fd)本质上就是:操作系统给“已打开资源”分配的一个编号。非负整数

文件描述符(File Descriptor,简称 FD)
是操作系统为了高效管理已被打开的文件或资源,而向应用程序返回的一个非负整数(通常是从 0 开始的数字索引)

文件描述符就是进程访问文件、管道、终端、网络连接等资源时使用的“操作系统编号”

文件描述符就是:某个进程打开资源后,操作系统给这个资源分配的编号。所以判断“是不是占用文件描述符”,你就看:
这个进程有没有打开文件、管道、socket、终端、设备,并且还没关闭?
有,那就占用 fd。

不是“文件自己占用文件描述符”,而是:
某个进程打开了文件、管道、socket、终端之后,操作系统给这个进程分配的一个编号,这个编号就是文件描述符。





可以把文件描述符理解成:
一个进程手里拿着的“资源号码牌”。
不是“文件自己占用文件描述符”,而是:
某个进程打开了文件、管道、socket、终端之后,操作系统给这个进程发了一个编号,这个编号就是文件描述符。






分配编号后,后续操作就是围绕这个编号来的。代码通常不直接用 fd 编号;真正直接使用 fd 编号的是底层系统调用和操作系统内核








进程启动后默认会有3个文件描述符

进程默认有 fd=0、fd=1、fd=2,是为了让每个程序都有统一的输入、正常输出、错误输出通道。
所以程序不需要知道自己是在终端里运行、被管道连接、被重定向到文件,还是在 Docker/Celery 里运行;它只需要读 fd=0,写 fd=1,报错写 fd=2





只有当代码需要操作系统帮你“打开某种外部资源”时,才会分配fd,才会占用文件描述符。

只要你打开了这些资源,就通常会占 fd:
文件
管道
socket 网络连接
终端
设备文件






不是所有情况都是一个操作占一个fd











每个进程都有自己的一张“文件描述符表”,这张表里面记录:fd 号码 -> 这个 fd 指向什么资源。文件描述符不是全局唯一的,而是进程内部的编号。

文件描述符是进程级别的资源编号。
可以这样记:
每个进程有一张 fd 表;
fd 只是这张表里的编号;
不同进程可以有相同的 fd 编号;
线程共享所属进程的 fd 表;
fork / subprocess 创建子进程时,子进程可能继承父进程的一些 fd。

子进程 clangd 打开的文件,不会算到父进程 里面
Linux 里每个进程都有自己的 FD 表。
比如
PID 8 Celery worker child
PID 79001 mcp-language-server
PID 79016 clangd
它们各自有自己的:
/proc/8/fd
/proc/79001/fd
/proc/79016/fd
所以你看到:
ls /proc/8/fd | wc -l
1024
说明是 Celery 子进程 PID 8 自己的 FD 满了。
如果是 clangd 打开太多文件,应该看:
ls /proc/79016/fd | wc -l
而不是看 /proc/8/fd。


为什么说fd是进程才有?文件描述符是操作系统为了管理某个进程打开的资源而分配的编号

子进程会继承父进程的一些 fd

每个进程都有自己的 FD 表
但子进程刚创建出来时,系统会把父进程 FD 表里的部分条目“复制一份”给子进程
所以不是“父子进程共用同一张 FD 表”,而是:
父进程有自己的 FD 表
子进程也有自己的 FD 表
但是子进程刚出生时,它的 FD 表内容,很多是从父进程那里复制来的









父子进程的 fd 表不是同一张表,父进程和子进程都有自己的 fd 表

子进程启动后,也有自己的 fd=0、fd=1、fd=2。默认情况下,它们连接到和父进程一样的终端;只有你显式写了 PIPE、重定向文件等,才会把它们改接到别的地方

线程有没有文件描述符?线程属于同一个进程,所以同一个进程内的多个线程共享同一张 fd 表。

一切皆文件。Linux 把很多资源统一成“可以 open/read/write/close 的对象”。

在 Linux 和 Unix
操作系统中,有一个非常核心的哲学叫做
“一切皆文件”。这意味着不仅普通的文本文件是文件,网络连接(Socket)、管道(Pipe)、标准输入输出、甚至硬件设备,在系统底层都被抽象成了“文件”。而
FD 就是访问这些资源的“钥匙”。





/dev/null 理解成:
Linux 提供的一个“特殊文件入口”,你往里面写东西,系统直接丢掉。
它不是普通的 .txt 文件,不会真的保存 hello。







操作 fd,就是操作 fd 指向的资源

fd 就是进程访问资源的编号;操作 fd,就是让操作系统根据这个编号找到背后的文件、终端、管道、socket 等资源,然后对它执行读、写、关闭等操作



单进程允许打开的最大文件描述符数量的限制。cat /proc/PID/limits | grep “open files”

“单进程允许打开的最大文件描述符数量限制”就是:一个进程最多能同时打开多少个文件、管道、socket、设备等资源


硬限制本身也是进程的属性。进程启动时,通常从父进程继承 soft limit 和 hard limit。






ulimit -n 当前 shell 以及由这个 shell 启动的子进程默认会继承的 fd 限制



如何修改soft limit









看某个进程当前打开的fd总个数。ls /proc//fd | wc -l

先列出这个进程所有 fd
再统计有多少行
得到这个进程当前打开了多少个 fd



查看进程具体打开了哪些资源 lsof(list open files) -p 。ls -l /proc/进程PID/fd




fd 表示这个进程打开了某个资源;后面的字母表示这个 fd 对这个资源的访问方式。即这个资源是以什么方式被打开的:读、写、读写。


进程当前打开的 fd 都指向哪些资源,并找出重复最多的资源

遍历 PID=513811 进程的所有 fd,查看每个 fd 指向哪里,把相同目标归类统计,按数量从多到少排序,显示前 50 个

forfdin/proc/513811/fd/*;doreadlink"$fd";done|sort|uniq-c|sort-nr|head-50









版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 3:43:41

为什么dubbo和openFeign都是通过动态代理的方式发起调用

因为它们要实现同一个目标&#xff1a;让“远程调用”在代码层看起来像“本地方法调用”而实现这个目标的关键设计就是&#xff1a;动态代理 方法拦截1 一句话本质Dubbo / OpenFeign “接口 服务入口” 动态代理 “拦截方法调用 → 转换成远程请求”2 为什么必须用动态代理…

作者头像 李华
网站建设 2026/6/10 3:36:32

STM32F103超频实战:用CubeMX和Keil把ADC时钟从14M提到36M,采样率翻倍

STM32F103超频实战&#xff1a;突破ADC时钟限制的性能优化指南引言在嵌入式开发领域&#xff0c;性能优化始终是开发者追求的核心目标之一。对于使用STM32F103系列MCU的工程师而言&#xff0c;ADC采样率往往成为系统性能的瓶颈。官方手册明确标注ADC时钟不得超过14MHz&#xff…

作者头像 李华
网站建设 2026/6/10 3:31:44

Word域代码进阶:教你用\#“0”指令自定义参考文献引用格式(如[1,2,3])

Word域代码深度解析&#xff1a;打造专业级参考文献引用格式定制方案在学术写作或技术文档创作中&#xff0c;参考文献引用格式的规范性直接影响作品的专业程度。许多用户在使用Word的交叉引用功能时&#xff0c;常常受限于默认的[1][2][3]格式&#xff0c;而期刊或出版机构往往…

作者头像 李华
网站建设 2026/6/10 3:09:26

想做陪诊小程序,源码怎么挑才少踩坑?

最近身边有几个朋友在琢磨陪诊方向的创业&#xff0c;不过第一步选源码就被难住了。市面上陪诊系统的源码看着一搜一大把&#xff0c;但用过的都知道&#xff0c;水比想象中深——有些界面做得花哨&#xff0c;跑起来才发现一堆暗坑。刚开始特别容易只看演示漂不漂亮。实际上陪…

作者头像 李华