fd 是什么

1. 全称

File Descriptor,文件描述符

2. 核心一句话

Linux 下一切皆文件:普通文件、TCP连接、UDP套接字、管道、终端、socket、定时器,在内核里全部统一当成文件管理,内核给每一个打开的资源分配一个非负整数编号,这个编号就是 fd。

3. 举最简单例子

程序启动默认自带 3 个 fd:

  • 0:标准输入 stdin(控制台输入)
  • 1:标准输出 stdout(打印日志)
  • 2:标准错误 stderr(报错信息)

你打开一个文本文件,操作系统返回数字 3,那这个文件的 fd=3;
建立一条TCP客户端连接,返回 4,这条网络连接 fd=4。

4. fd 存在在哪?

每个进程单独维护一张 文件描述符表

  • key:fd 数字
  • value:指向内核全局的文件对象(socket/文件/管道)

不同进程的 fd 互不干扰,进程A的fd=3 和进程B的fd=3 是完全不同的资源。

5. 关键特性(面试必考点)

  1. 资源占用,有上限
    系统通过 ulimit -n 限制单个进程最大fd数量,默认一般 1024。
    如果不断新建TCP连接、打开文件不关闭,fd 数字持续上涨,打满上限就报错:
    too many open files

  2. 不调用 close(),fd 不会释放

  • 正常:连接关闭/文件close → fd回收,数字复用
  • 泄漏:goroutine永久阻塞、连接忘记关闭 → fd永久占用,慢慢耗尽
  1. IO多路复用 select/poll/epoll 操作的对象就是 fd
    我们把一堆 socket fd 注册到epoll,内核监控这些fd是否可读可写。

6. 区分两个容易混淆的点(对应你前面的问题)

  1. 百万fd(socket连接):只是内核里一串数字,占用内存极小,epoll可以轻松管理几十万上百万;
  2. 百万goroutine分别阻塞在每个fd上:每个goroutine有栈、运行时元数据,内存开销巨大,不能无限开;

总结

fd是文件描述符,Linux一切皆文件,打开文件、网络socket、管道都会由内核分配一个整型编号用来标识资源。每个进程有fd上限,资源不关闭会造成fd泄漏,达到上限后无法新建文件或网络连接,epoll、select等IO多路复用都是基于fd实现事件监听。