2011-06-17 52 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()