• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >python > 解决Python中由于logging模块误用导致的内存泄露

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

作者: 字体:[增加 减小] 来源:互联网

通过本文主要向大家介绍了python logging模块,python logging,logging python name,python中logging,python logging.info等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

首先介绍下怎么发现的吧, 线上的项目日志是通过 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)

</div>

当然测试环境是开 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

</div>

主要调用了 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)

</div>

logging 模块为了保证同一个名称引用同一个日志实例,所以就把所有的日志实例全部存 在了一个 loggerDict 的字典里, 所以除非程序退出, 创建的日志实例引用是不会释放的, 所以日志实例里的 handlers 也不会释放. 之前我又用的对象的 id 来作为日志名称 的一部分, 所以 SyslogHandler 创建的 UDP 连接就一直被占用导致了过多的 UDP 连接.

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

logging.Logger.manager.loggerDict.pop(self._logger_name)
self.logger.manager = None
self.logger.handlers = []

</div>

按说只加上上面第一行的代码就应该释放了, 但是没有, 所以又有了第三行代码, SyslogHandler 才最终释放, 这个问题暂时还不知道为什么, 还需要再查查.

2015-03-30 更新 如果日志名称是以 . 分隔, logging 模块则会将最后一部分作为日志名, 并往上去寻找 父 Logger, 如果找不到则创建 PlaceHolder 对象作为父, 并引用 Logger.

比如创建的 Logger 名称为 a.b.c, 那么实际的名称则为 c, 并将 b 作为 c 的父, a 作为 b 的 父, 如果没有该名称的 Logger 则创建 PlaceHolder 对象作为代替, PlaceHolder 会创建对当前 Logger 的引用. 所以需要被回收的日志对象名称里不应包含 .

</div>

您可能想查找下面的文章:

  • Python中内置的日志模块logging用法详解
  • 详解Python中的日志模块logging
  • Python同时向控制台和文件输出日志logging的方法
  • Python同时向控制台和文件输出日志logging的方法
  • 解决Python中由于logging模块误用导致的内存泄露
  • Python中使用logging模块打印log日志详解
  • python logging类库使用例子
  • python logging类库使用例子
  • Python中logging模块的用法实例
  • Python中使用logging模块代替print(logging简明指南)

相关文章

  • python实现定制交互式命令行的方法
  • 关于你不想知道的所有Python3 unicode特性
  • 初步理解Python进程的信号通讯
  • 学习python之编写简单乘法口诀表实现代码
  • python 中文乱码问题深入分析
  • python实现一次创建多级目录的方法
  • Python实现LRU算法的2种方法
  • 用Python解析XML的几种常见方法的介绍
  • Python中的变量和作用域详解
  • python计算方程式根的方法

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • Python实现冒泡,插入,选择排序简单实例
    • python 从远程服务器下载东西的代码
    • python获取当前时间对应unix时间戳的方法
    • 利用python实现数据分析
    • Python实现二叉搜索树
    • 浅析Python基础-流程控制
    • Python中下划线的使用方法
    • 解决python3 urllib中urlopen报错的问题
    • 使用Python判断IP地址合法性的方法实例
    • Python实现的多线程端口扫描工具分享

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有