2011-06-17 28 views
2

我有一个服务器子类产生线程响应处理程序,处理程序依次启动应用程序线程。一切都很顺利,除非我使用ObjGraph我看到正在运行的应用程序线程的正确数量(我正在进行负载测试并阻止了35个应用程序实例的运行)。Python多线程应用程序与特定于线程的记录器实例的内存泄漏

调用objgraph.typestats()提供了每个对象当前在解释器中生存多少个实例的细分(根据GC)。查看内存泄漏的输出,我发现700个记录器实例 - 这将是服务器产生的响应处理器的总数。

我已经调用logger.removehandler(memoryhandler)和logger.removehandler(filehandler),当应用程序线程退出run()方法以确保没有对记录器实例的延迟引用时,记录器实例也完全隔离在应用程序线程内(没有外部引用)。作为消除这些记录器实例的最后一步,run()中的最后一条语句是del self.logger

要在init()中获取记录器,我提供一个适当大的随机数来命名它,文件访问 - 我使用相同的大数字作为日志文件名的一部分,以避免应用程序日志冲突。

长和短是我有700个跟踪GC的记录器实例,但只有35个活动线程 - 我该如何去关闭这些记录器?一个更麻烦的工程师解决方案是创建一个记录器池,并在应用程序线程的生命周期中获取一个,但是当GC应该自动处理时,创建更多的代码来维护。

回答

0

不要创建潜在无限数量的记录器,这不是很好的做法 - 如文档here所述,还有其他方法可以获取上下文相关信息到日志中。

你也不需要有一个记录器作为一个实例属性:记录器是单身,所以你可以从任何地方通过名字获得一个特定的记录器。推荐的做法是名伐木工人在使用

logger = logging.getLogger(__name__) 

这足以满足大多数情况下的模块级。

从你的问题我不能告诉你是否赞赏处理程序和记录器不是同一件事 - 例如你谈论removeHandler调用(这可能释放处理程序实例,因为它们的引用计数为零,但这样做不会释放任何记录器实例)。

一般来说,记录器是根据您的应用程序的部分命名的,它们会生成感兴趣的事件。

如果你想让每个线程去例如写入不同的文件,每次都可以创建一个新的文件名,然后在完成时关闭处理程序,并且线程即将终止(即关闭对于释放处理程序资源非常重要)。或者,您可以使用日志输出中包含的线程标识符或其他标识符将所有内容记录到一个文件中,并在日志文件中使用后处理。

0

我使用logging.Logger()时遇到了相同的内存泄漏,并且您可以尝试手动关闭处理FD时,记录仪是无用的,如:

for handler in logger.handlers: 
    handler.close()