Python中由於logging模組誤用導致的記憶體泄露的解決方案

來源:互聯網
上載者:User

   Python中由於logging模組誤用導致的記憶體泄露的解決方案

        這篇文章主要介紹瞭解決Python中由於logging模組誤用導致的記憶體泄露,針對由於過多的UDP串連所產生的問題,需要的朋友可以參考下

  首先介紹下怎麼發現的吧, 線上的項目日誌是通過 logging 模組打到 syslog 裡, 跑了一段時間後發現 syslog 的 UDP 串連超過了 8W, 沒錯是 8 W. 主要是 logging 模組用的不對

  我們之前有這麼一個需求, 就是針對每一個串連日誌輸出當前串連的資訊, 所以每一個 串連就建立了一個日誌執行個體, 並分配一個 Formatter, 建立日誌執行個體為了區分其他串連 所以我就簡單粗暴的用了當前對象的 id 來作為日誌名稱:

  ?

1 2 3 4 5 6 7 import logging     class Connection(object): def __init__(self): self._logger_name = "Connection.{}".format(id(self)) self.logger = logging.getLogger(self._logger_name)

  當然測試環境是開 DEBUG, 開 DEBUG 就不會往 syslog 裡打, 所以不會出現 UDP 串連數 過多, 也就不會知道有記憶體泄露的, 我們來看看這樣為什麼會導致記憶體泄露, 首先看看 getLogger 的代碼:

  ?

1 2 3 4 5 6 7 8 9 10 def getLogger(name=None): """ Return a logger with the specified name, creating it if necessary.   If no name is specified, return the root logger. """ if name: return Logger.manager.getLogger(name) else: return root

  主要調用了 Logger.manager.getLogger, 這個函數有下面一段程式碼片段

  ?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 if name in self.loggerDict: rv = self.loggerDict[name] if isinstance(rv, PlaceHolder): ph = rv rv = (self.loggerClass or _loggerClass)(name) rv.manager = self self.loggerDict[name] = rv self._fixupChildren(ph, rv) self._fixupParents(rv) else: rv = (self.loggerClass or _loggerClass)(name) rv.manager = self self.loggerDict[name] = rv self._fixupParents(rv)

  logging 模組為了保證同一個名稱引用同一個日誌執行個體,所以就把所有的日誌執行個體全部存 在了一個 loggerDict 的字典裡, 所以除非程式退出, 建立的日誌執行個體引用是不會釋放的, 所以日誌執行個體裡的 handlers 也不會釋放. 之前我又用的對象的 id 來作為日誌名稱 的一部分, 所以 SyslogHandler 建立的 UDP 串連就一直被佔用導致了過多的 UDP 串連.

  為瞭解決這個問題我在串連關閉的時候加入了如下代碼:

  ?

1 2 3 logging.Logger.manager.loggerDict.pop(self._logger_name) self.logger.manager = None self.logger.handlers = []

  按說只加上上面第一行的代碼就應該釋放了, 但是沒有, 所以又有了第三行代碼, SyslogHandler 才最終釋放, 這個問題暫時還不知道為什麼, 還需要再查查.

  2015-03-30 更新 如果日誌名稱是以 . 分隔, logging 模組則會將最後一部分作為日誌名, 並往上去尋找 父 Logger, 如果找不到則建立 PlaceHolder 對象作為父, 並引用 Logger.

  比如建立的 Logger 名稱為 a.b.c, 那麼實際的名稱則為 c, 並將 b 作為 c 的父, a 作為 b 的 父, 如果沒有該名稱的 Logger 則建立 PlaceHolder 對象作為代替, PlaceHolder 會建立對當前 Logger 的引用. 所以需要被回收的日誌對象名稱裡不應包含 .

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.