解决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 相关文章推荐
tornado捕获和处理404错误的方法
Feb 26 Python
Python入门之modf()方法的使用
May 15 Python
Python中的ctime()方法使用教程
May 22 Python
Python 基础教程之闭包的使用方法
Sep 29 Python
Python实现螺旋矩阵的填充算法示例
Dec 28 Python
Python脚本完成post接口测试的实例
Dec 17 Python
基于keras 模型、结构、权重保存的实现
Jan 24 Python
python实现梯度法 python最速下降法
Mar 24 Python
Linux安装Python3如何和系统自带的Python2并存
Jul 23 Python
python如何爬取网页中的文字
Jul 28 Python
Python限制内存和CPU使用量的方法(Unix系统适用)
Aug 04 Python
详解Python之Scrapy爬虫教程NBA球员数据存放到Mysql数据库
Jan 24 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 return语句的另一个作用
2014/07/30 PHP
windows下配置php5.5开发环境及开发扩展
2014/12/25 PHP
php 猴子摘桃的算法
2017/06/20 PHP
PHP PDOStatement::errorInfo讲解
2019/01/31 PHP
php抽象类和接口知识点整理总结
2019/08/02 PHP
PhpStorm连接服务器并实现自动上传功能
2020/12/09 PHP
几个高效,简洁的字符处理函数
2007/04/12 Javascript
不用写JS也能使用EXTJS视频演示
2008/12/29 Javascript
说明你的Javascript技术很烂的五个原因
2011/04/26 Javascript
jQuery.each()用法分享
2012/07/31 Javascript
jquery ready(fn)事件使用介绍
2013/08/21 Javascript
js 操作select与option(示例讲解)
2013/12/20 Javascript
iframe里面的元素触发父窗口元素事件的jquery代码
2014/10/19 Javascript
js实现交换运动效果的方法
2015/04/10 Javascript
jQuery模拟360浏览器切屏效果幻灯片(附demo源码下载)
2016/01/29 Javascript
JS作用域链详解
2017/06/26 Javascript
vue+vux实现移动端文件上传样式
2017/07/28 Javascript
vue动态路由实现多级嵌套面包屑的思路与方法
2017/08/16 Javascript
javaScript产生随机数的用法小结
2018/04/21 Javascript
vue-cli3.X快速创建项目的方法步骤
2019/11/14 Javascript
vue路由分文件拆分管理详解
2020/08/13 Javascript
three.js如何实现3D动态文字效果
2021/03/03 Javascript
[01:34]2016国际邀请赛中国区预选赛IG战队教练采访
2016/06/27 DOTA
Python常用模块用法分析
2014/09/08 Python
python基于queue和threading实现多线程下载实例
2014/10/08 Python
简单介绍Python中的len()函数的使用
2015/04/07 Python
Python中列表和元组的使用方法和区别详解
2020/12/30 Python
解决PyCharm控制台输出乱码的问题
2019/01/16 Python
Python常用特殊方法实例总结
2019/03/22 Python
基于django ManyToMany 使用的注意事项详解
2019/08/09 Python
通信工程毕业生自荐信
2013/11/01 职场文书
致铅球运动员加油稿
2014/02/13 职场文书
服务承诺书格式
2014/05/21 职场文书
基层组织建设年活动总结
2015/05/09 职场文书
2019优秀干部竞聘演讲稿范文!
2019/07/02 职场文书
SQL Server中使用表变量和临时表
2022/05/20 SQL Server