1

我最近在我的服务器上遇到了一个关于“打开的文件太多”的异常。我检查了 lsof,果然,有一堆 PDF 文件保持打开状态(都在同一个目录中)。这个特定的文件是通过 Django FileField 管理的。我试图追踪我的项目中任何通过名称显式打开文件的地方,但我只能找到一个地方,据我所知,文件在那里被正确关闭。文件可能在其他地方保持打开状态,但我不知道如何找出实际上保持文件打开状态的代码。我试过简单地 grepping 调用 open() 和 file(),但没有运气。

有什么方法可以系统地追踪导致文件打开的代码行?

编辑:我了解如何正确打开/关闭文件。我的问题是,是否有一种方法可以追踪留下的现有代码行使文件处于打开状态。

4

2 回答 2

4

使用时open,请尝试将其用作上下文管理器。这样,无论发生什么,当你完成它时它都会关闭:

with open('file.txt', 'r') as fin:
    # Access fin like normal

# No matter what happens, after the block, it's closed!

或者,您可以用您自己的函数替换实例open并为您执行一些额外的日志记录:close

def my_open(filename, *args):
    logger.debug('Opening %s' % filename)
    return open(filename, *args)

def my_close(file_obj):
    logger.debug('Closing %s' % file_obj.name)
    return file_obj.close()

作为最后的手段,如果您无法访问有问题的代码,或者更改它会很麻烦,您可以尝试猴子修补功能。

import traceback
class MyFile(file):
    @staticmethod
    def open(*args, **kwargs):
        return MyFile(*args, **kwargs)

    def __init__(self, *args, **kwargs):
        self._file = self._open(*args, **kwargs)
        print('Opening %s from %s' % (
            self._file.name, ''.join(traceback.format_stack())))

    def close(self):
        print('Closing file %s from %s' % (
            self._file.name, ''.join(traceback.format_stack())))
        self._file.close()

# Now the monkey-patching
file = MyFile
MyFile._open = open
open = MyFile.open

o = open('hello', 'w+')

它当然不是世界上最漂亮的东西,但如果你能够对其进行猴子补丁,那么你至少能够处理遗留代码。

于 2013-05-10T17:35:45.503 回答
0

您是否依赖垃圾收集器来关闭您的文件?IE 句柄超出范围,即使您“关闭”了文件,它也不会消失,直到 GC 运行。如果对象链永远不会超出范围,GC 就无法收集它。此外,如果 GC 没有机会运行,它们也不会被收集。

我在一个长时间运行的进程中遇到了同样的问题,并通过重新设计我的系统来“解决”它,这样所有文件访问都发生在一个子对象内。该对象在使用完毕后从引用链中删除,或者发生了一些错误。这允许 GC 收集句柄。

于 2013-05-10T17:50:25.233 回答