Linux下用getrlimit(RLIMIT_NOFILE,&rlim)可直接获取当前进程文件描述符软硬限,软限生效、硬限为setrlimit提升上限,需包含<sys/resource.h>和<unistd.h>,rlim_cur为RLIM_INFINITY时需判断,fork子进程继承但独立于父进程后续修改;ulimit-n显示shell初始值而非程序运行时值,应于main开头调用getrlimit确认真实限制;systemd或Docker会覆盖该值;setrlimit提限须早于打开fd且受权限约束;Windows无等价机制, HANDLE数无法用统一接口查询。

Linux 下用 getrlimit 查看当前进程的文件描述符上限
直接调用 getrlimit(RLIMIT_NOFILE, &rlim) 即可拿到软限(rlim.rlim_cur)和硬限(rlim.rlim_max)。软限是当前生效值,硬限是能通过 setrlimit 提升的天花板——但普通进程通常无权突破硬限。
常见错误是只读 /proc/self/limits 文本文件,这虽可行但开销大、需解析、还依赖 procfs 挂载;而 getrlimit 是纯系统调用,零解析、无 IO、所有 Linux 发行版都支持。
- 必须包含
<sys/resource.h>和<unistd.h> -
rlimit结构体中rlim_cur可能为RLIM_INFINITY(值为 -1),打印前建议判断 - 该值针对**当前进程**,fork 后子进程继承该限制,但与父进程后续调用
setrlimit无关
为什么 ulimit -n 显示的值和 getrlimit 返回不一致?
终端里执行 ulimit -n 看到的是 shell 启动时继承的软限,而你的 C++ 程序运行后可能已被其他代码(比如某些框架或初始化逻辑)调用过 setrlimit 修改过。更关键的是:ulimit 显示的是当前 shell 的限制,不是你程序的运行时限制。
实操建议:在程序入口(如 main() 开头)立刻调用 getrlimit 并打印,才能反映真实值。别依赖外部命令或假设它和 shell 一致。
立即学习“C++免费学习笔记(深入)”;
- shell 的
ulimit -n只影响它 fork 出的子进程的初始值,不锁定已运行进程 - systemd 服务可能被
LimitNOFILE=覆盖,此时getrlimit返回的就是 systemd 设置后的值 - 容器环境(如 Docker)中,
--ulimit nofile=...会作用于 init 进程,你的程序继承它
修改上限要用 setrlimit,但注意权限和顺序
想临时提上限,得先用 setrlimit(RLIMIT_NOFILE, &new_rlim)。但有两个硬约束:软限不能超过硬限;非 root 进程只能把软限提到硬限,不能提高硬限本身。
典型失败场景:程序启动后先打开了大量 fd,再试图调高软限——失败,因为内核要求新软限 ≤ 当前已用 fd 数(防止“假提升”)。所以必须在打开任何文件前尽早设置。
- 推荐在
main()最开头、甚至__attribute__((constructor))函数里调用 - 若需突破系统硬限(如从 1024 提到 65536),必须提前用
sudo ulimit -Hn 65536或配置/etc/security/limits.conf -
setrlimit失败时errno会是EPERM(权限不足)或EINVAL(数值非法),务必检查返回值
跨平台?Windows 没有等价机制
Windows 不使用“文件描述符”抽象,而是 HANDLE,且没有全局统一的 per-process 上限概念。C runtime 层面有 _setmaxstdio() 控制 stdio 流数量(默认 512),但这和内核句柄数无关;真正瓶颈是 GetProcessHandleCount() 返回的句柄总数,上限由系统内存和对象管理器决定,无法用类似 getrlimit 的接口查询。
如果你写的是跨平台代码,别试图封装一个通用函数——Linux 用 getrlimit,Windows 直接跳过或记录为“不可查”。强行抽象只会掩盖差异,导致线上 Linux 机器 fd 耗尽时 Windows 侧毫无预警。
实际部署时,Linux 服务必须监控 /proc/PID/fd/ 目录项数量,这是唯一可靠的方式;而 Windows 更应关注 PerfMon 中 “Process\Handle Count” 计数器。



















