解决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文件读写操作与linux shell变量命令交互执行的方法
Jan 14 Python
Python实现的圆形绘制(画圆)示例
Jan 31 Python
Python数据分析之双色球基于线性回归算法预测下期中奖结果示例
Feb 08 Python
python 用lambda函数替换for循环的方法
Jun 09 Python
Python Web编程之WSGI协议简介
Jul 18 Python
Django中ORM外键和表的关系详解
May 20 Python
python 计算一个字符串中所有数字的和实例
Jun 11 Python
cProfile Python性能分析工具使用详解
Jul 22 Python
pytorch实现用CNN和LSTM对文本进行分类方式
Jan 08 Python
pycharm中如何自定义设置通过“ctrl+滚轮”进行放大和缩小实现方法
Sep 16 Python
Python+Appium新手教程
Apr 17 Python
Python爬取某拍短视频
Jun 11 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编程网上资源导航
2006/10/09 PHP
PHP 采集获取指定网址的内容
2010/01/05 PHP
php 5.6版本中编写一个PHP扩展的简单示例
2015/01/20 PHP
PHP Static延迟静态绑定用法分析
2016/03/16 PHP
php实现的AES加密类定义与用法示例
2018/01/29 PHP
初窥JQuery(一)jquery选择符 必备知识点
2010/11/25 Javascript
window.dialogArguments 使用说明
2011/04/11 Javascript
很棒的学习jQuery的12个网站推荐
2011/04/28 Javascript
基于JQuery的抓取博客园首页RSS的代码
2011/12/01 Javascript
Jquery左右滑动插件之实现超级炫酷动画效果附源码下载
2015/12/02 Javascript
基于jquery实现简单的分页控件
2016/03/17 Javascript
使用jQuery调用XML实现无刷新即时聊天
2016/08/07 Javascript
微信小程序开发入门基础教程
2017/04/19 Javascript
小程序封装路由文件和路由方法(5种全解析)
2019/05/26 Javascript
详解在Vue.js编写更好的v-for循环的6种技巧
2020/04/14 Javascript
javascript实现前端分页功能
2020/11/26 Javascript
JS常用跨域方法实现原理解析
2020/12/09 Javascript
python字符串加密解密的三种方法分享(base64 win32com)
2014/01/19 Python
Python 正则表达式入门(中级篇)
2016/12/07 Python
Python多线程扫描端口代码示例
2018/02/09 Python
Python数据可视化 pyecharts实现各种统计图表过程详解
2019/08/15 Python
pytorch自定义初始化权重的方法
2019/08/17 Python
python 画出使用分类器得到的决策边界
2019/08/21 Python
Python的控制结构之For、While、If循环问题
2020/06/30 Python
聊聊python中的异常嵌套
2020/09/01 Python
python 爬虫基本使用——统计杭电oj题目正确率并排序
2020/10/26 Python
html5 canvas合成海报所遇问题及解决方案总结
2017/08/03 HTML / CSS
联想墨西哥官方网站:Lenovo墨西哥
2016/08/17 全球购物
Omio英国:搜索并比较便宜的巴士、火车和飞机
2019/08/27 全球购物
linux面试相关问题
2012/08/11 面试题
法律专业应届本科毕业生求职信
2013/10/25 职场文书
2014年五一促销活动方案
2014/03/09 职场文书
工程管理英文求职信
2014/03/18 职场文书
主题教育活动总结
2014/05/05 职场文书
《蚂蚁和蝈蝈》教学反思
2016/02/22 职场文书
python实现图片批量压缩
2021/04/24 Python