怎样用Python检测未关闭的文件描述符?

来源:站长源码作者:俊华头衔:草根站长
导读:本期聚焦于小伙伴创作的《怎样用Python检测未关闭的文件描述符?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《怎样用Python检测未关闭的文件描述符?》有用,将其分享出去将是对创作者最好的鼓励。

在Python程序运行过程中,打开文件、网络连接、管道等资源时都会分配对应的文件描述符,如果忘记手动关闭或者异常场景下没有正确释放,就会出现未关闭的文件描述符,长期运行会导致资源耗尽。我们可以通过多种方式检测这类问题。

怎样用Python检测未关闭的文件描述符?

基础检测:使用标准库psutil

psutil是跨平台的系统监控库,可以获取进程当前的文件描述符使用情况,通过对比不同阶段的文件描述符数量,就能判断是否存在未关闭的情况。

首先需要安装psutil库:

pip install psutil

下面是一个简单的检测示例,对比打开文件前后的描述符数量变化:

import psutil
import os

# 获取当前进程对象
current_process = psutil.Process(os.getpid())

# 统计打开前的文件描述符数量
before_open = len(current_process.open_files())
print(f"打开前文件描述符数量:{before_open}")

# 模拟打开文件但不关闭
f = open("test.txt", "w")
# 这里没有调用f.close()

# 统计打开后的文件描述符数量
after_open = len(current_process.open_files())
print(f"打开后文件描述符数量:{after_open}")

# 输出未关闭的文件信息
if after_open > before_open:
    print("存在未关闭的文件描述符:")
    for file_info in current_process.open_files():
        print(f"文件路径:{file_info.path},文件描述符:{file_info.fd}")

上下文管理器场景的检测

使用with语句可以自动关闭文件描述符,但如果自定义的资源类没有实现上下文管理器协议,还是可能出现泄漏。我们可以通过重写__del__方法或者结合弱引用检测对象是否被回收,间接判断描述符是否关闭。

下面是一个自定义资源类的检测示例:

import weakref

class CustomResource:
    def __init__(self, name):
        self.name = name
        self.fd = open(f"{name}.txt", "w")  # 模拟分配文件描述符
        print(f"资源{name}初始化,分配描述符")

    def close(self):
        if not self.fd.closed:
            self.fd.close()
            print(f"资源{name}的描述符已关闭")

    def __del__(self):
        # 对象被销毁时如果描述符未关闭,打印警告
        if hasattr(self, "fd") and not self.fd.closed:
            print(f"警告:资源{self.name}被销毁时描述符未关闭")

# 检测对象回收情况
def resource_finalizer(ref):
    print("资源对象已被垃圾回收")

res = CustomResource("demo")
# 创建弱引用,对象被回收时触发回调
ref = weakref.ref(res, resource_finalizer)
# 不手动调用close,也不删除引用,触发__del__
del res

长期运行服务的监控方案

对于长期运行的服务,我们可以定期采样进程的文件描述符数量,设置阈值告警。下面是一个简单的定时监控示例:

import psutil
import os
import time

def monitor_fd(interval=5, threshold=100):
    """
    定期监控文件描述符数量
    :param interval: 监控间隔,单位秒
    :param threshold: 告警阈值
    """
    process = psutil.Process(os.getpid())
    while True:
        fd_count = len(process.open_files())
        print(f"当前文件描述符数量:{fd_count}")
        if fd_count > threshold:
            print(f"告警:文件描述符数量超过阈值{threshold}")
            # 这里可以添加告警逻辑,比如发送通知
        time.sleep(interval)

if __name__ == "__main__":
    # 启动监控,间隔3秒,阈值设为50
    monitor_fd(interval=3, threshold=50)

常见泄漏原因与修复建议

未关闭的文件描述符通常由以下原因导致:

  • 打开资源后忘记调用close方法,也没有使用with语句
  • 异常场景下,close方法没有被执行,比如没有在finally块中释放资源
  • 自定义资源类没有实现上下文管理器协议,使用with语句也无法自动释放

对应的修复建议:

  • 优先使用with语句管理资源,例如with open("test.txt", "r") as f:,离开with块会自动关闭
  • 如果必须手动管理,将close方法放在finally块中执行,确保异常时也能释放
  • 自定义资源类实现__enter__和__exit__方法,支持上下文管理器协议

补充:使用lsof命令辅助检测

除了Python代码内检测,我们也可以使用系统命令lsof查看指定进程的文件描述符情况,适合定位线上问题。例如查看进程ID为1234的进程打开的所有文件:

lsof -p 1234

如果需要过滤Python进程的文件描述符,可以结合grep使用:

lsof -p 1234 | grep python

Python文件描述符资源泄漏psutilGC修改时间:2026-07-24 01:21:23

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。