解决Python中由于logging模块误用导致的内存泄露


Posted in Python onApril 23, 2015

首先介绍下怎么发现的吧, 线上的项目日志是通过 logging 模块打到 syslog 里, 跑了一段时间后发现 syslog 的 UDP 连接超过了 8W, 没错是 8 W. 主要是 logging 模块用的不对

我们之前有这么一个需求, 就是针对每一个连接日志输出当前连接的信息, 所以每一个 连接就创建了一个日志实例, 并分配一个 Formatter, 创建日志实例为了区分其他连接 所以我就简单粗暴的用了当前对象的 id 来作为日志名称:

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 的代码:

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, 这个函数有下面一段代码片段

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 连接.

为了解决这个问题我在连接关闭的时候加入了如下代码:

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 的引用. 所以需要被回收的日志对象名称里不应包含 .

Python 相关文章推荐
python创建和使用字典实例详解
Nov 01 Python
Python中类的继承代码实例
Oct 28 Python
深入解析Python设计模式编程中建造者模式的使用
Mar 02 Python
使用python遍历指定城市的一周气温
Mar 31 Python
DataFrame中去除指定列为空的行方法
Apr 08 Python
python 实现分页显示从es中获取的数据方法
Dec 26 Python
Django组件cookie与session的具体使用
Jun 05 Python
Python list与NumPy array 区分详解
Nov 06 Python
python求解汉诺塔游戏
Jul 09 Python
浅谈Python 钉钉报警必备知识系统讲解
Aug 17 Python
如何用tempfile库创建python进程中的临时文件
Jan 28 Python
python爬虫如何解决图片验证码
Feb 14 Python
粗略分析Python中的内存泄漏
Apr 23 #Python
使用beaker让Facebook的Bottle框架支持session功能
Apr 23 #Python
用Python编写脚本使IE实现代理上网的教程
Apr 23 #Python
在Python的Bottle框架中使用微信API的示例
Apr 23 #Python
最基础的Python的socket编程入门教程
Apr 23 #Python
利用Python实现简单的相似图片搜索的教程
Apr 23 #Python
以911新闻为例演示Python实现数据可视化的教程
Apr 23 #Python
You might like
PHP 字符串加密函数(在指定时间内加密还原字符串,超时无法还原)
2010/04/28 PHP
php在程序中将网页生成word文档并提供下载的代码
2012/10/09 PHP
PHP设计模式之迭代器模式的深入解析
2013/06/13 PHP
PHP回调函数简单用法示例
2019/05/08 PHP
js本身的局限性 别让javascript做太多事
2010/03/23 Javascript
eval与window.eval的差别分析
2011/03/17 Javascript
Javascript实现真实字符串剩余字数提示的实例代码
2013/10/22 Javascript
JavaScript Array对象扩展indexOf()方法
2014/05/09 Javascript
php读取sqlite数据库入门实例代码
2014/06/25 Javascript
javascript实现修改微信分享的标题内容等
2014/12/11 Javascript
jQuery创建DOM元素实例解析
2015/01/19 Javascript
JS数组array元素的添加和删除方法代码实例
2015/06/01 Javascript
angularjs在ng-repeat中使用ng-model遇到的问题
2016/01/21 Javascript
Vue 2.5 Level E 发布了: 新功能特性一览
2017/10/24 Javascript
element 结合vue 在表单验证时有值却提示错误的解决办法
2018/01/22 Javascript
详解Vue.js v-for不支持IE9的解决方法
2018/12/29 Javascript
更强大的vue ssr实现预取数据的方式
2019/07/19 Javascript
vue中使用腾讯云Im的示例
2020/10/23 Javascript
开源软件包和环境管理系统Anaconda的安装使用
2017/09/04 Python
YUV转为jpg图像的实现
2019/12/09 Python
Python3 解决读取中文文件txt编码的问题
2019/12/20 Python
MNIST数据集转化为二维图片的实现示例
2020/01/10 Python
Tensorflow设置显存自适应,显存比例的操作
2020/02/03 Python
python实现跨excel sheet复制代码实例
2020/03/03 Python
解决python脚本中error: unrecognized arguments: True错误
2020/04/20 Python
python中如何写类
2020/06/29 Python
Django数据统计功能count()的使用
2020/11/30 Python
CSS 3.0 结合video视频实现的创意开幕效果
2020/06/01 HTML / CSS
松下电器美国官方商店:Panasonic美国
2016/10/14 全球购物
汇集了世界上最好的天然和有机美容产品:LoveLula
2018/02/05 全球购物
给全校老师的建议书
2014/03/13 职场文书
节能宣传周活动总结
2014/05/08 职场文书
酒店工程部经理岗位职责
2015/04/09 职场文书
小学运动会加油词
2015/07/18 职场文书
2016年中秋节慰问信
2015/12/01 职场文书
Android开发手册Chip监听及ChipGroup监听
2022/06/10 Java/Android