总结python 三种常见的内存泄漏场景


Posted in Python onNovember 20, 2020

概要

不要以为 Python 有自动垃圾回收就不会内存泄漏,本着它有“垃圾回收”我有“垃圾代码”的精神,现在总结一下三种常见的内存泄漏场景。

无穷大导致内存泄漏

如果把内存泄漏定义成只申请不释放,那么借着 Python 中整数可以无穷大的这个特点,我们一行代码就可以完成内存泄漏了。

i = 1024 ** 1024 ** 1024

循环引用导致内存泄漏

引用记数器 是 Python 垃圾回收机制的基础,如果一个对象的引用数量不为 0 那么是不会被垃圾回收的,我们可以通过 sys.getrefcount 来得到给定对象的引用数量。

In [1]: import sys                               

In [2]: a = {'name':'tom','age':16}                       

In [3]: sys.getrefcount(a)  # 由于 getrefcount 内部也会临时的引用 a 所以,使得计数器的值变成了 2 。               
Out[3]: 2

In [4]: b = a                                  

In [5]: sys.getrefcount(a)                           
Out[5]: 3

先来看一个循环引用的场景。

#!/usr/bin/evn python3

import sys
import time
import threading


class Person(object):
  free_lock = threading.Condition()

  def __init__(self, name: str = ""):
    """
    Parameters
    ----------
    name: str
      姓名

    best_friend: str
      最要好的朋友名
    """
    self._name = name
    self._best_friend = None

  @property
  def best_friend(self, person: "Person"):
    return self._best_friend

  @best_friend.setter
  def best_friend(self, friend: "Person"):
    self._best_friend = friend

  def __str__(self):
    """
    """
    return self._name

  def __del__(self):
    """
    """
    self.free_lock.acquire()
    print(f"{self._name} 要 GG 了,现在释放它的内存空间。")
    sys.stderr.flush()
    self.free_lock.release()


def mem_leak():
  """
  循环引用导致内存泄漏
  """
  zhang_san = Person(name='张三')
  li_si = Person("李四")

  # 构造出循环引用
  # 李四的好友是张三
  li_si.best_friend = zhang_san
  # 张三的好友是李四
  zhang_san.best_friend = li_si


if __name__ == "__main__":
  for i in range(3):
    time.sleep(0.01)
    print(f"{i}")
    mem_leak()

  print("mem_leak 执行完成了.")
  time.sleep(5)

运行效果。

python3 main.py
0
1
2
mem_leak 执行完成了.
张三 要 GG 了,现在释放它的内存空间。
李四 要 GG 了,现在释放它的内存空间。
张三 要 GG 了,现在释放它的内存空间。
李四 要 GG 了,现在释放它的内存空间。
张三 要 GG 了,现在释放它的内存空间。
李四 要 GG 了,现在释放它的内存空间

由于循环引用的存在,使得 mem_leak 函数就行执行完了其内部的局部变量引用计数器也不为 0 ,所以内存得不到及时的释放。释放这部分内存有两个途径 1、 被 Python 内部的循环检测机制发现了; 2、进程退出前的集中释放。

tracemalloc 可以在一定程序上帮我们发现问题,在此就不讲怎么用了,我们直接上解决方案。Python 为程序员提供了弱引用,通过这种方式可以不增加对象引用计数器的数值,这成为了我们打破循环引用的一种手段。

In [1]: import sys                               

In [2]: import weakref                             

In [3]: from main import Person                         

In [4]: tom = Person('tom')                           

In [5]: sys.getrefcount(tom)                          
Out[5]: 2

In [6]: p = weakref.ref(tom)                          

In [7]: sys.getrefcount(tom)  # 弱引用不会增加计数器的值                        
Out[7]: 2

现在使用 weakref 技术来改造我们的代码。

#!/usr/bin/evn python3


import sys
import time
import weakref
import threading


class Person(object):
  free_lock = threading.Condition()

  def __init__(self, name: str = ""):
    """
    Parameters
    ----------
    name: str
      姓名

    best_friend: str
      最要好的朋友名
    """
    self._name = name
    self._best_friend = None

  @property
  def best_friend(self, person: "Person"):
    return self._best_friend

  @best_friend.setter
  def best_friend(self, friend: "Person"):
    self._best_friend = weakref.ref(friend)

  def __str__(self):
    """
    """
    return self._name

  def __del__(self):
    """
    """
    self.free_lock.acquire()
    print(f"{self._name} 要 GG 了,现在释放它的内存空间。")
    sys.stderr.flush()
    self.free_lock.release()


def mem_leak():
  """
  循环引用导致内存泄漏
  """
  zhang_san = Person(name='张三')
  li_si = Person("李四")

  # 构造出循环引用
  # 李四的好友是张三
  li_si.best_friend = zhang_san
  # 张三的好友是李四
  zhang_san.best_friend = li_si


if __name__ == "__main__":
  for i in range(3):
    time.sleep(0.01)
    print(f"{i}")
    mem_leak()

  print("mem_leak 执行完成了.")
  time.sleep(5)

运行效果。

python3 main.py
0
张三 要 GG 了,现在释放它的内存空间。
李四 要 GG 了,现在释放它的内存空间。
1
张三 要 GG 了,现在释放它的内存空间。
李四 要 GG 了,现在释放它的内存空间。
2
张三 要 GG 了,现在释放它的内存空间。
李四 要 GG 了,现在释放它的内存空间。
mem_leak 执行完成了.

可以看到现在一旦函数执行完成,其内部的局部变量的内存就会得到释放,非常的及时。

外面库导致内存泄漏

这种情况我也只遇到过一次,之前 mysql-connector-python 的内存泄漏,导致我的程序跑着跑着占用的内存就越来越大;最后我们返的 C 语言扩展禁用之后就没有问题了。

以上就是总结python 三种常见的内存泄漏场景的详细内容,更多关于python 内存泄漏的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
python中的多重继承实例讲解
Sep 28 Python
Python使用xlrd模块操作Excel数据导入的方法
May 26 Python
浅谈tensorflow1.0 池化层(pooling)和全连接层(dense)
Apr 27 Python
Python实现将Excel转换成为image的方法
Oct 23 Python
Python发送邮件测试报告操作实例详解
Dec 08 Python
python获取本机所有IP地址的方法
Dec 26 Python
python删除文件夹下相同文件和无法打开的图片
Jul 16 Python
python使用html2text库实现从HTML转markdown的方法详解
Feb 21 Python
在spyder IPython console中,运行代码加入参数的实例
Apr 20 Python
Django表单提交后实现获取相同name的不同value值
May 14 Python
Python通用唯一标识符uuid模块使用案例
Sep 10 Python
pycharm 多行批量缩进和反向缩进快捷键介绍
Jan 15 Python
Python偏函数实现原理及应用
Nov 20 #Python
python与idea的集成的实现
Nov 20 #Python
安装pyinstaller遇到的各种问题(小结)
Nov 20 #Python
python3 re返回形式总结
Nov 20 #Python
python 实现图片修复(可用于去水印)
Nov 19 #Python
python 删除系统中的文件(按时间,大小,扩展名)
Nov 19 #Python
Python并发爬虫常用实现方法解析
Nov 19 #Python
You might like
php扩展ZF――Validate扩展
2008/01/10 PHP
php实现无限级分类实现代码(递归方法)
2011/01/01 PHP
php中url传递中文字符,特殊危险字符的解决方法
2013/08/17 PHP
Thinkphp实现MySQL读写分离操作示例
2014/06/25 PHP
php常量详细解析
2015/10/27 PHP
PHP使用PDO调用mssql存储过程的方法示例
2017/10/07 PHP
用dom+xhtml+css制作的一个相册效果代码打包下载
2008/01/24 Javascript
javascript不同页面传值的改进版
2008/09/30 Javascript
select 控制网页内容隐藏于显示的实现代码
2010/05/25 Javascript
jQuery on()方法使用技巧详解
2015/04/16 Javascript
使用jQuery Mobile框架开发移动端Web App的入门教程
2016/05/17 Javascript
JavaScript实现横线提示输入验证码随输入验证码输入消失的方法
2016/09/24 Javascript
JS实现div模块的截图并下载功能
2017/10/17 Javascript
HTML5+JS+JQuery+ECharts实现异步加载问题
2017/12/16 jQuery
VUE实现自身整体组件销毁的示例代码
2020/01/13 Javascript
十分钟教你上手ES2020新特性
2020/02/12 Javascript
javascript canvas API内容整理
2020/02/16 Javascript
[00:09]DOTA2新版本PA至宝特效动作展示
2014/11/19 DOTA
[33:17]OG vs VGJ.T 2018国际邀请赛小组赛BO2 第二场 8.18
2018/08/19 DOTA
Python2.x中文乱码问题解决方法
2015/06/02 Python
python 与GO中操作slice,list的方式实例代码
2017/03/20 Python
Centos 升级到python3后pip 无法使用的解决方法
2018/06/12 Python
python操作excel文件并输出txt文件的实例
2018/07/10 Python
Numpy 改变数组维度的几种方法小结
2018/08/02 Python
pyside+pyqt实现鼠标右键菜单功能
2020/12/08 Python
Python3进制之间的转换代码实例
2019/08/24 Python
Django 创建后台,配置sqlite3教程
2019/11/18 Python
THE OUTNET美国官网:国际设计师品牌折扣网站
2017/03/07 全球购物
毕业生如何写自荐信
2014/03/26 职场文书
《槐乡五月》教学反思
2014/04/25 职场文书
银行竞聘上岗演讲稿
2014/09/12 职场文书
委托证明模板
2014/09/16 职场文书
教师业务学习材料
2014/12/16 职场文书
九寨沟导游词
2015/02/02 职场文书
市场部经理岗位职责
2015/02/02 职场文书
创业计划书之都市休闲农庄
2019/12/28 职场文书