Watch at Ease看见世界,读懂生活。

科技 · 实用指南

Python resource_tracker 报 leaked shared_memory:只指定一个生命周期责任方

修改 track 前先画清创建者、附加者与 tracker 家族。只让一个进程负责 unlink,并同时验证存活与清理。

Original diagram mapping a shared-memory creator, attachers, tracker family and one unlink owner.
原创示意图:修改 track 前先指定一个共享内存生命周期责任方。 Watch at Ease

resource_tracker 警告不一定表示漏了 close()。两个独立 Python 进程家族也可能同时认为自己拥有同一个 POSIX 共享内存名称,先退出的 tracker 会过早删除仍在使用的名称。

修复首先是责任归属。记录 Python 版本、平台、启动关系、创建者、附加者与退出顺序,为每个名称只指定一个 unlink 责任方,再决定各进程的 track。

冻结进程拓扑

记录操作系统、Python 版本、启动方法、服务管理器、创建者 PID、每个附加者 PID、启动方式和退出顺序。不同终端、subprocess 树、容器与 uWSGI worker 要先视为可能不同的 tracker 家族。

记录精确名称、create、track 以及每个 close/unlink 调用。保留原始警告与后续 attach 是否失败,不能用旧警告冒充当前版本行为。

分开句柄、映射与名称寿命

close() 结束本对象的访问。POSIX 下 unlink() 删除名称,现有映射与最终回收遵循平台语义。一次本地 close 并不能证明名称仍可附加或已有清理责任方。

每个名称一行,列出创建者、活动附加者、tracker 家族、长期责任方、close 责任与唯一 unlink 责任。多个 unlink 责任方会冲突,没有责任方才是真泄漏风险。

先选责任模型,再选 track

单一 multiprocessing 家族可让共享 tracker 处理异常退出,但应用仍要关闭每个句柄并保留一个正常 unlink 路径。不要让每个 worker 都 unlink。

对独立或跨语言进程,选择寿命长于消费者的协调者。Python 3.13+ 的非责任独立附加者只有在另一进程或系统明确负责清理时才使用 track=False。

明确版本与平台分支

Python 3.13 以前没有公开 track 参数。不要把私有 unregister 或 monkey patch 当通用生产修复;应升级、合并进程家族或让显式协调者管理清理并测试回滚。

Windows 忽略 track;POSIX 名称可持续到 unlink 与最终 unmap。跨平台服务必须分别写验收预期。

运行双向退出测试

启动责任方与两个非责任方,写入 generation 标记,然后停止一个非责任方。新的附加者仍应打开同名对象并读到标记,否则清理过早。

再停止另一个非责任方,最后让责任方执行唯一 unlink。此后新 attach 必须失败;异常终止要在可丢弃夹具中另测,并把警告与数据寿命结果分开记录。

Original decision diagram requiring shared-memory survival after a non-owner exits and cleanup after the owner exits.
原创示意图:退出测试必须同时通过存活与最终清理两道门。 Watch at Ease