这是一个很酷的问题。
我有一个 python 脚本(main),它调用一个 python 模块 (foo.py),而 python 模块又调用另一个 python 模块 (barwrapper.py) 使用 LoadLibrary 动态打开和访问 libbar.so 库。
libbar 和链的整个其余部分打开并创建文件来执行他们的任务。当我们在主 python 脚本中发出 rmtree 以摆脱导入模块创建的临时目录时,就会出现问题。rmtree 在脚本末尾调用,就在退出之前。调用失败,因为目录包含.nfs-whatever
隐藏文件,我猜是已删除的文件。这些文件显然在代码中保持打开状态,迫使 nfs 将它们移动到这些.nfs-whatever
文件中,直到释放文件描述符。这种情况在其他文件系统中不会出现,因为与保存的描述符关联的文件被有效地删除,但内核可以访问,直到描述符关闭。
我们强烈怀疑 .so 库泄漏了文件描述符,这些未关闭的文件在清理时破坏了 rmtree 派对。我想过在 barwrapper 中卸载 .so 文件,但显然没有办法做到这一点,而且我不确定 dynnloader 是否真的会从进程空间中删除库并关闭描述符,或者它是否只是将其标记为卸载,仅此而已,等待被其他东西替换, 但随着描述符泄露。
我真的想不出这个问题的其他解决方法(除了修复泄漏,这是我们不想做的事情,因为它是第 3 方库)。显然,它只发生在 nfs 上。您知道我们可以尝试修复它吗?
内核会跟踪文件描述符,因此即使您让 python 卸载 .so 并释放内存,它也不会知道关闭泄漏的文件描述符。唯一想到的是在分叉后导入 .so,并且仅在分叉的子进程退出后进行清理(并且内核在退出时隐式关闭文件句柄)。
好的解决方案是修复句柄泄漏,但如果您不确定谁在泄漏,也许 strace 调用将帮助您定位泄漏并将错误提交给第三方库的维护者(或者更好的是,如果它是一个开源库,请尝试提交补丁;))。
另一方面,也许 nfs 分区上的卸载/挂载可以帮助强制关闭手柄。