解决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 相关文章推荐
VSCode下配置python调试运行环境的方法
Apr 06 Python
django 多数据库配置教程
May 30 Python
Python 查找list中的某个元素的所有的下标方法
Jun 27 Python
对python生成业务报表的实例详解
Feb 03 Python
如何更优雅地写python代码
Jul 02 Python
Python Threading 线程/互斥锁/死锁/GIL锁
Jul 21 Python
Python+OpenCV+图片旋转并用原底色填充新四角的例子
Dec 12 Python
Python selenium的基本使用方法分析
Dec 21 Python
Pytorch技巧:DataLoader的collate_fn参数使用详解
Jan 08 Python
python GUI库图形界面开发之PyQt5美化窗体与控件(异形窗体)实例
Feb 25 Python
pandas数据选取:df[] df.loc[] df.iloc[] df.ix[] df.at[] df.iat[]
Apr 24 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
dede3.1分页文字采集过滤规则详说(图文教程)
2007/04/03 PHP
joomla内置的表单验证功能使用方法
2010/06/11 PHP
服务器web工具 php环境下
2010/12/29 PHP
php调整gif动画图片尺寸示例代码分享
2013/12/05 PHP
PHP缓存机制Output Control详解
2014/07/14 PHP
php实现的微信红包算法分析(非官方)
2015/09/25 PHP
PHP中如何防止外部恶意提交调用ajax接口
2016/04/11 PHP
js 提交和设置表单的值
2008/12/19 Javascript
jQuery 使用手册(六)
2009/09/23 Javascript
基于jQuery的history历史记录插件
2010/12/11 Javascript
使用jQuery全局事件ajaxStart为特定请求实现提示效果的代码
2010/12/30 Javascript
多个表单中如何获得这个文件上传的网址实现js代码
2013/03/25 Javascript
JavaScript实现两个Table固定表头根据页面大小自行调整
2014/01/03 Javascript
JS 排序输出实现table行号自增前端动态生成的tr
2014/08/13 Javascript
AJAX和jQuery动态加载数据的实现方法
2016/12/05 Javascript
js实现截图保存图片功能的代码示例
2017/02/16 Javascript
Bootstrap禁用响应式布局的实现方法
2017/03/09 Javascript
详解如何用webpack4从零开始构建react开发环境
2019/01/27 Javascript
element-ui 本地化使用教程详解
2019/10/28 Javascript
vue开发chrome插件,实现获取界面数据和保存到数据库功能
2020/12/01 Vue.js
[01:45]2014DOTA2 TI预选赛预选赛 大神专访第二弹!
2014/05/20 DOTA
python实现的AES双向对称加密解密与用法分析
2017/05/02 Python
Python编写Windows Service服务程序
2018/01/04 Python
python查询mysql,返回json的实例
2018/03/26 Python
Python实现判断并移除列表指定位置元素的方法
2018/04/13 Python
python 顺时针打印矩阵的超简洁代码
2018/11/14 Python
Python实现AES加密,解密的两种方法
2020/10/03 Python
pandas按条件筛选数据的实现
2021/02/20 Python
HTML5 和小程序实现拍照图片旋转、压缩和上传功能
2018/10/08 HTML / CSS
Oroton中国官网:澳洲知名奢侈配饰品牌
2017/03/26 全球购物
法国票务网站:Ticketmaster法国
2018/07/09 全球购物
小学教师岗位职责
2013/11/25 职场文书
党课知识竞赛主持词
2014/04/01 职场文书
学习党章的体会
2014/11/07 职场文书
运动会100米加油稿
2015/07/21 职场文书
家访教师心得体会
2016/01/23 职场文书