zoukankan      html  css  js  c++  java
  • 48、python内存泄露

    python内存泄露

    起因

    内存泄露指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。导致程序运行速度减慢甚至系统崩溃等严重后果。有 del() 函数的对象间的循环引用是导致内存泄漏的主凶

    img

    方案

    不使用一个对象时使用:delobject 来删除一个对象的引用计数就可以有效防止内存泄漏问题。通过Python 扩展模块 gc 来查看不能回收的对象的详细信息。可以通过 sys.getrefcount(obj) 来获取对象的引用计数,并根据返回值是否为 0 来判断是否内存泄漏。

    但是由于gc垃圾收集机制,要遍历所有被垃圾收集器管理的python对象(包括垃圾和非垃圾对象),该过程比较耗时可能会造成程序卡顿,会对某些对内存、cpu要求较高的场景造成性能影响。那怎么才能优雅地避免内存泄露呢?

    编写安全的代码

    比如对于下面发生内存泄露的cycle_ref函数,在函数结束前解除循环引用,即可解决内存泄露问题。

    def cycle_ref():
        a1 = A()
        a2 = A()
     
        a1.child = a2
        a2.child = a1
     
        # 解除循环引用,避免内存泄露
        a1.child  = None
        a2.child  = None
    

    但是对于上述方法,我们有可能会忘记那一两行无关紧要的代码而造成灾难性后果,毕竟老虎也有打盹的时候。那怎么办?不要着急,Python已经为我们考虑到这点:弱引用。

    弱引用

    Python标准库提供了weakref模块,弱引用不会在引用计数中计数,其主要目的是解决循环引用。并非所有的对象都支持weakref,例如list和dict就不支持。下面是weakref比较常用的方法:

    """
    1. class weakref.ref(object[, callback]) :创建一个弱引用对象,object是被引用的对象,callback是回调函数(当被引用对象被删除时,调用该回调函数)
    
    2.weakref.proxy(object[, callback]):创建一个用弱引用实现的代理对象,参数同上
    
    3.weakref.getweakrefcount(object) :获取对象object关联的弱引用对象数
    
    4.weakref.getweakrefs(object):获取object关联的弱引用对象列表
    
    5.class weakref.WeakKeyDictionary([dict]):创建key为弱引用对象的字典
    
    6.class weakref.WeakValueDictionary([dict]):创建value为弱引用对象的字典
    
    7.class weakref.WeakSet([elements]):创建成员为弱引用对象的集合对象
    """
    

    同样对于上面发生内存泄露的cycle_ref函数,使用weakref稍加改造,便可更安全地解决内存泄露问题:

    import weakref
     
    class A(object):
        def __init__(self):
            self.data = [x for x in range(100000)]
            self.child = None
     
        def __del__(self):
            pass
     
    def cycle_ref():
        a1 = A()
        a2 = A()
     
        a1.child = weakref.proxy(a2)
        a2.child = weakref.proxy(a1)
     
    if __name__ == '__main__':
        import time
        while True:
            time.sleep(0.5)
            cycle_ref()
    
  • 相关阅读:
    Windows下 如何添加开机启动项
    Android在 普通类(非Activity,多数为Adapter) 中 传输数据为空值 解决方法 :在startActivity 用 intent传输数据
    Android 从ImageView中获取Bitmap对象方法
    剑指offer(纪念版)读书笔记【实时更新】
    剑指offer(纪念版) 面试题3:二维数组中的查找
    C++ sizeof 误区 大公司面试题
    51 nod 1521 一维战舰 时间复杂度O(n),同 Codeforces 567D. One-Dimensional Battle Ships 有详细注释
    51nod 1126 求递推序列的第N项 思路:递推模拟,求循环节。详细注释
    51nod 1451 合法三角形 判斜率去重,时间复杂度O(n^2)
    关于JetBrains CLion 激活 (CLion License Activation)的解决办法,带hosts详细修改
  • 原文地址:https://www.cnblogs.com/amgulen/p/14046683.html
Copyright © 2011-2022 走看看