游乐游手机版
首页/业界动态/文章详情

四个实验彻底搞懂Linux句柄泄漏和Too many open files

时间:2026-06-15 16:22
这篇文章,我们将通过几个简单脚本,亲手模拟一场典型的“句柄泄漏事故”,让你直观理解其发生机制与复现方法。在上一篇文章中,我们分析了一个常见的线上故障: Too many open files → 服务拒绝连接 很多开发者会疑惑:这个问题究竟是如何触发的?能否在本地环境进行复现? 本文我们将直接使用几

这篇文章,我们将通过几个简单脚本,亲手模拟一场典型的“句柄泄漏事故”,让你直观理解其发生机制与复现方法。

在上一篇文章中,我们分析了一个常见的线上故障:

Too many open files → 服务拒绝连接

很多开发者会疑惑:这个问题究竟是如何触发的?能否在本地环境进行复现?

本文我们将直接使用几个简易脚本,亲手复现一场“句柄泄漏事故”。

什么是文件描述符(FD)

在 Linux 系统中,一切资源皆被视为文件:

  • 普通文件
  • 网络 Socket
  • Pipe(管道)
  • 设备节点

这些资源均通过文件描述符(FD)进行统一管理。

每个进程可使用的 FD 数量都有上限:

ulimit -n

常见配置值:

  • 1024(系统默认)
  • 65535(经过优化后的典型值)

一旦 FD 被耗尽,便会触发:

Too many open files

实验一:最简单的 FD 泄漏场景

演示脚本(未主动关闭文件):

# fd_leak_file.py
import time
fds = []
while True:
    f = open("/tmp/test_fd.txt", "w")
    fds.append(f)  # ❗没有关闭
    print("opened:", len(fds))
    time.sleep(0.01)

运行实验:

ulimit -n 10000
python3 fd_leak_file.py
opened: 9993
opened: 9994
opened: 9995
opened: 9996
opened: 9997
Traceback (most recent call last):
  File "file_os.py", line 7, in 
OSError: [Errno 24] Too many open files: '/tmp/test_fd.txt'
# 检查文件描述符
[root@localhost ~]# ll /proc/4013078/fd -ltr
...
l-wx------ 1 root root 64  3月 24 22:27 9993 -> /tmp/test_fd.txt
l-wx------ 1 root root 64  3月 24 22:27 9994 -> /tmp/test_fd.txt
l-wx------ 1 root root 64  3月 24 22:27 9995 -> /tmp/test_fd.txt
l-wx------ 1 root root 64  3月 24 22:27 9996 -> /tmp/test_fd.txt

监控截图:

\

由此可见,只要持续打开文件而不关闭,FD 必然被耗尽。

实验二:模拟 Socket 连接泄漏

该场景更贴近实际服务:

# fd_leak_socket.py
import socket
import time
sockets = []
while True:
    s = socket.socket()
    s.connect(("127.0.0.1", 80))
    sockets.append(s)  # ❗不关闭
    print("socket:", len(sockets))
    time.sleep(0.01)

运行现象:

#脚本执行情况
socket: 9997
Traceback (most recent call last):
  File "fd_leak_socket.py", line 8, in 
  File "/usr/lib64/python3.7/socket.py", line 151, in __init__
OSError: [Errno 24] Too many open files
#检查句柄情况
[root@localhost ~]# ls -ltr /proc/1831260/fd
...
lrwx------ 1 root root 64  3月 25 16:29 104 -> 'socket:[1039854483]'
lrwx------ 1 root root 64  3月 25 16:29 103 -> 'socket:[1039854482]'
lrwx------ 1 root root 64  3月 25 16:29 102 -> 'socket:[1039854481]'
lrwx------ 1 root root 64  3月 25 16:29 101 -> 'socket:[1039854480]'
lrwx------ 1 root root 64  3月 25 16:29 100 -> 'socket:[1039854479]'
lrwx------ 1 root root 64  3月 25 16:29 10 -> 'socket:[1039845307]'
lrwx------ 1 root root 64  3月 25 16:29 1 -> /dev/pts/0
lrwx------ 1 root root 64  3月 25 16:29 0 -> /dev/pts/0
lrwx------ 1 root root 64  3月 25 16:30 9999 -> 'socket:[1040097407]'

lFD 数量持续增长,最终程序报错:

\

实验三(重点):触发 Pipe 泄漏

该场景正是许多线上故障的根源:

# fd_leak_pipe.py
import os
import time
pipes = []
while True:
    r, w = os.pipe()
    pipes.append((r, w))  # ❗不关闭
    print("pipe:", len(pipes))
    time.sleep(0.01)

验证步骤:
首先找到进程 PID

ps -ef | grep fd_leak_pipe

查看 FD 数量

[root@localhost ~]# ls -ltr /proc/1923060/fd
...
l-wx------ 1 root root 64  3月 25 16:36 9722 -> 'pipe:[1040687058]'
lr-x------ 1 root root 64  3月 25 16:36 9721 -> 'pipe:[1040687058]'
l-wx------ 1 root root 64  3月 25 16:36 9720 -> 'pipe:[1040687057]'
lr-x------ 1 root root 64  3月 25 16:36 9719 -> 'pipe:[1040687057]'
ls /proc/

/fd | wc -l

你会发现:

  • 已打开的文件描述符数量持续攀升
  • 短时间内即逼近系统上限

查看 FD 类型:

ls -l /proc/

/fd | grep pipe pipe:[xxxx] pipe:[xxxx] pipe:[xxxx]

该现象与众多线上生产故障完全吻合。

实验四:模拟真实服务场景(子进程泄漏)

此场景最贴近实际生产环境:

# fd_leak_subprocess.py
import subprocess
import time
procs = []
while True:
    p = subprocess.Popen(
        ["echo", "hello"],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE
    )
    procs.append(p)  # ❗不 wait、不关闭
    print("proc:", len(procs))
    time.sleep(0.01)

该实验会导致:

  • Pipe 数量急剧增加
  • 子进程不断堆积
  • 文件描述符迅速膨胀引发爆炸

与真实服务(如文档转换、后台任务执行)的故障模式高度一致。

为什么会发生泄漏?

根本原因只有一个:资源被申请后,始终未进行释放。

文件描述符(FD)泄漏可归纳为四大类:

  • 文件打开后未关闭
  • Socket 连接未释放
  • Pipe 管道未关闭
  • 子进程未等待(导致管道残留)

正确写法(避免泄漏):

import os
for i in range(10000):
    r, w = os.pipe()
    os.close(r)
    os.close(w)

或对子进程做:

p = subprocess.Popen(...)
p.wait()

如何快速判断是否存在泄漏?

方法1:观察 FD 数量是否持续增长

watch -n 1 "ls /proc/

/fd | wc -l"

方法2:按类型统计 FD 占比

ls -l /proc/

/fd | awk '{print $NF}' | cut -d: -f1 | sort | uniq -c

方法3:查看 Socket 状态

ss -antp

实验总结

上述几个实验印证了一个道理:文件描述符泄漏并非复杂难题,本质上是“忘记关闭资源”导致的。

但在生产环境中,由于:

  • 并发量高
  • 调用链复杂
  • 业务链路漫长

极易演变成灾难性后果:

FD耗尽 → 无法 accept → 服务雪崩

如果你在线上遇到:

  • 服务突然拒绝连接
  • 日志频繁出现Too many open files

第一件该做的事:

ls /proc/

/fd | wc -l

亲手动手模拟一遍,远比阅读十篇理论文章更有效。

来源:https://www.51cto.com/article/840899.html
上一篇告别啰嗦代码!2026年.NET开发者必学的15个简写运算符 下一篇年国内GEO优化公司全景评测:五家服务商值得关注
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
长安汽车明年一季度发布首款车载人形机器人小安
业界动态 · 2026-06-29

长安汽车明年一季度发布首款车载人形机器人小安

长安汽车公布机器人战略,采用“1+N+X”布局,联合头部伙伴攻克大脑、能源、驱动技术。人形机器人“小安”身高169cm,体重69kg,移动速度0 8m s,具备40个自由度,续航超2小时。预计明年一季度发布首款车载组件机器人,已在广州车展展示。

中国信科刷新光通信世界纪录 每秒可下载1.4万部4K电影
业界动态 · 2026-06-29

中国信科刷新光通信世界纪录 每秒可下载1.4万部4K电影

3月25日,光通信领域迎来又一个里程碑:中国信科集团光通信技术和网络全国重点实验室联合鹏城实验室、烽火藤仓光纤科技有限公司,成功实现了2 5Pb s 24芯光纤超大容量实时光传输,再次刷新了世界纪录。 这一研究成果不仅入选国际顶级光通信会议OFC(2026)并荣获“高分论文”称号,还受国际权威SCI

美国调查18万辆特斯拉Model3车门应急释放装置易找性
业界动态 · 2026-06-29

美国调查18万辆特斯拉Model3车门应急释放装置易找性

美国国家公路交通安全管理局对约17 9万辆2024款特斯拉Model3启动缺陷调查,焦点在于车门应急释放装置是否不易找到且标识不清。该调查源于一份缺陷请愿,不意味着立即召回,但可能引发后续监管措施。

doc个人图书馆停服 创始人称无偿转让失败
业界动态 · 2026-06-29

doc个人图书馆停服 创始人称无偿转让失败

运营长达20年,累计服务8000万用户的360doc个人图书馆,最终还是迎来了谢幕时刻。2026年5月1日,这个承载着无数用户收藏记忆的知名平台将正式停止服务——关停原因并非用户流失,而是始终未能寻得一位能够安全接管的合适人选。 创始人蔡智在告别信中坦言,近两个月来,他一直在尝试将360doc无偿转

年Q1随身WiFi实测安全靠谱高性价比机型推荐
业界动态 · 2026-06-29

年Q1随身WiFi实测安全靠谱高性价比机型推荐

2025年10月,艾瑞咨询正式授予飞猫“AI WiFi品类开创者”认证,紧接着CIC也将其认定为“多网融合自由切换技术服务首创者”。这些权威认证背后,折射出一个清晰的市场趋势:移动办公、户外出行、宿舍上网等场景的需求正在快速增长,随身WiFi几乎已成为不少用户的刚需装备。但问题也随之而来——网络卡顿