解决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编程时利用wxPython来支持多线程的方法
Apr 07 Python
PyQt5 pyqt多线程操作入门
May 05 Python
Python中一些不为人知的基础技巧总结
May 19 Python
Python实现查找最小的k个数示例【两种解法】
Jan 08 Python
Python 脚本的三种执行方式小结
Dec 21 Python
tensorflow 保存模型和取出中间权重例子
Jan 24 Python
Tensorflow 模型转换 .pb convert to .lite实例
Feb 12 Python
Python+OpenCV实现图像的全景拼接
Mar 05 Python
Python多个装饰器的调用顺序实例解析
May 22 Python
keras实现VGG16方式(预测一张图片)
Jul 07 Python
Python中openpyxl实现vlookup函数的实例
Oct 28 Python
Python中生成随机数据安全性、多功能性、用途和速度方面进行比较
Apr 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生成略缩图代码
2012/07/16 PHP
非常精妙的PHP递归调用与静态变量使用
2012/12/16 PHP
jQuery 性能优化指南(3)
2009/05/21 Javascript
超级酷和最实用的jQuery实例收集(20个)
2010/04/21 Javascript
基于jQuery实现文本框缩放以及上下移动功能
2014/11/24 Javascript
AngularJS基础 ng-hide 指令用法及示例代码
2016/08/01 Javascript
Javascript+CSS3实现进度条效果
2016/10/28 Javascript
jQuery UI插件实现百度提词器效果
2016/11/21 Javascript
微信小程序 天气预报开发实例代码源码
2017/01/20 Javascript
NodeJS使用七牛云存储上传文件的方法
2017/07/24 NodeJs
js截取字符串功能的实现方法
2017/09/27 Javascript
Vue 使用 Mint UI 实现左滑删除效果CellSwipe
2018/04/27 Javascript
vuejs实现折叠面板展开收缩动画效果
2018/09/06 Javascript
vue实现分页组件
2020/06/16 Javascript
详解webpack引入第三方库的方式以及注意事项
2019/01/15 Javascript
vue watch关于对象内的属性监听
2019/04/22 Javascript
Weex开发之WEEX-EROS开发踩坑(小结)
2019/10/16 Javascript
vue 项目引入echarts 添加点击事件操作
2020/09/09 Javascript
wxpython中利用线程防止假死的实现方法
2014/08/11 Python
Python使用MD5加密字符串示例
2014/08/22 Python
Python中的zipfile模块使用详解
2015/06/25 Python
Python中异常重试的解决方案详解
2017/05/05 Python
Python学习笔记基本数据结构之序列类型list tuple range用法分析
2019/06/08 Python
PyTorch 对应点相乘、矩阵相乘实例
2019/12/27 Python
python代码如何注释
2020/06/01 Python
python如何调用php文件中的函数详解
2020/12/29 Python
python 统计list中各个元素出现的次数的几种方法
2021/02/20 Python
HTML5页面无缝闪开的问题及解决方案
2020/06/11 HTML / CSS
澳大利亚儿童精品仓库:Goo & Co.
2019/06/20 全球购物
第一批党的群众路线教育实践活动工作总结
2014/03/03 职场文书
2014年会策划方案
2014/05/11 职场文书
2014年维修电工工作总结
2014/11/20 职场文书
夫妻分居协议书范文
2014/11/26 职场文书
离婚协议书范文2014(夫妻感情破裂)
2014/12/14 职场文书
2015年见习期个人工作总结
2015/05/28 职场文书
运动员入场前导词
2015/07/20 职场文书