• Python垃圾回收机制及gc模块详解:内存泄露的例子


    标记清理是用来解决循环引用的。分代回收针对所有的新创建即进入0代的对象和进入1、2代的对象。。这样就解释了python“引用计数为主。标记清理+分代回收为辅”的垃圾回收原理,因为循环引用毕竟是少数情况。

    # 没有循环引用的情况,随着del、函数退出等触发条件,立即删除所占用内存
    import gc
    import sys
    gc.set_debug(gc.DEBUG_STATS|gc.DEBUG_COLLECTABLE|gc.DEBUG_UNCOLLECTABLE|gc.DEBUG_SAVEALL|gc.DEBUG_LEAK)
    
    a=[]
    b=[]
    print(hex(id(a)))
    print(hex(id(b)))
    a.append(b)
    print('a refcount:',sys.getrefcount(a))  # 2
    print('b refcount:',sys.getrefcount(b))  # 3
     
    del a  #  这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理,毕竟gc是根据阈值设置触发执行的,没有立即删除那么快
    del b  #  这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理
    print(gc.collect())  # 0
    #放在解释器里执行:
    >>> a=[] >>> b=[] >>> print(hex(id(a))) 0x102918788 >>> print(hex(id(b))) 0x1029187c8 >>> a.append(b) >>> print('a refcount:',sys.getrefcount(a)) # 2 a refcount: 2 >>> print('b refcount:',sys.getrefcount(b)) # 3 b refcount: 3 >>> ... del a # 这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理 >>> del b # 这里已经删除了,内存也被回收了,所以在gc进行垃圾回收的时候,不需要处理 >>> print(gc.collect()) # 0 gc: collecting generation 2... gc: objects in each generation: 4 0 4338 gc: objects in permanent generation: 0 gc: done, 0.0009s elapsed 0 -----没有任何对象被回收 >>>
    # 下面的示例是存在循环引用的情况,所以del删除的时候,只是删除了对象的引用,对象没有被删除,所以在gc进行垃圾回收的时候,所用内存经过标记清理和分代回收动作被回收掉
    
    a=[]
    b=[]
    print(hex(id(a)))
    print(hex(id(b)))
    a.append(b)
    b.append(a)
    del a
    del b
    print(gc.collect()) 
    # 放到python3.7解释器里执行
    >>> a=[]
    >>> b=[]
    >>> print(hex(id(a)))
    0x102828888
    >>> print(hex(id(b)))
    0x102828848
    >>> a.append(b)
    >>> b.append(a)
    >>> del a
    >>> del b
    >>> print(gc.collect())
    gc: collecting generation 2...
    gc: objects in each generation: 6 0 4336
    gc: objects in permanent generation: 0
    gc: collectable <list 0x102828888>
    gc: collectable <list 0x102828848>
    gc: done, 2 unreachable, 0 uncollectable, 0.0010s elapsed  2 0---表示存在2个不可达对象,0个不可以回收的对象
    2 --- 表示被回收了2个不可达对象
    >>>
    # 下面这段代码在python3.7中执行不存在内存泄露;但是在python2.7环境中存在内存泄露
    
    class A:
      def __del__(self):
          pass
    
    class B:
      def __del__(self):
          pass
     
    a=A()
    b=B()
    print(hex(id(a)))
    print(hex(id(a.__dict__)))
    a.b=b
    b.a=a
    del a
    del b
     
    print(gc.collect())
    print(gc.garbage)
    # pyhton3.7环境下执行
    >>> class A:
    ...   def __del__(self):
    ...       pass
    ...
    >>>
    ... class B:
    ...   def __del__(self):
    ...       pass
    ...
    >>>
    >>> a=A()
    >>> b=B()
    >>> print(hex(id(a)))
    0x10cfbfba8
    >>> print(hex(id(a.__dict__)))
    0x10ce64f78
    >>> a.b=b
    >>> b.a=a
    >>> del a
    >>> del b
    >>>
    ... print(gc.collect())
    gc: collecting generation 2...
    gc: objects in each generation: 683 3813 0
    gc: objects in permanent generation: 0
    gc: collectable <A 0x10cfbfba8>
    gc: collectable <B 0x10cfbfd68>
    gc: collectable <dict 0x10ce64f78>
    gc: collectable <dict 0x10cf083f0>
    gc: done, 4 unreachable, 0 uncollectable, 0.0008s elapsed   4 0 --- 存在4个不可达但是不存在不可以回收的对象,即4个不可达对象都可以回收
    4  ---回收了4个不可达的对象
    >>> print(gc.garbage)
    [<__main__.A object at 0x10cfbfba8>, <__main__.B object at 0x10cfbfd68>, {'b': <__main__.B object at 0x10cfbfd68>}, {'a': <__main__.A object at 0x10cfbfba8>}]
    >>>
    # python2.7环境下执行
    >>> class A:
    ...   def __del__(self):
    ...       pass
    ...
    gc: collecting generation 0...
    gc: objects in each generation: 658 3204 0
    gc: done, 0.0002s elapsed.
    >>>
    >>> class B:
    ...   def __del__(self):
    ...       pass
    ...
    >>> a=A()
    >>> b=B()
    >>> print(hex(id(a)))
    0x10239a2d8
    >>> print(hex(id(a.__dict__)))
    0x10239b050
    >>> a.b=b
    >>> b.a=a
    >>> del a
    >>> del b
    >>>
    ... print(gc.collect())
    gc: collecting generation 2...
    gc: objects in each generation: 16 3552 0
    gc: uncollectable <A instance at 0x10239a2d8>
    gc: uncollectable <B instance at 0x10239a320>
    gc: uncollectable <dict 0x10239b050>
    gc: uncollectable <dict 0x102398c58>
    gc: done, 4 unreachable, 4 uncollectable, 0.0008s elapsed.  4 4--- 存在4个不可达又不可以回收的对象
    4   --- 回收了4个不可达对象
    >>> print(gc.garbage)
    [<__main__.A instance at 0x10239a2d8>, <__main__.B instance at 0x10239a320>, {'b': <__main__.B instance at 0x10239a320>}, {'a': <__main__.A instance at 0x10239a2d8>}]
    >>>
    >>>

    这篇文章:https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p23_managing_memory_in_cyclic_data_structures.html举例的内存泄露的情况,也只有在python2.x中存在,python3.x貌似做了优化,并没有内存泄露:

    如果循环引用的对象自己还定义了自己的 __del__() 方法,那么会让情况变得更糟糕。 假设你像下面这样给Node定义自己的 __del__() 方法:

    # Class just to illustrate when deletion occurs
    class Data:
        def __del__(self):
            print('Data.__del__')
    
    # Node class involving a cycle
    class Node:
        def __init__(self):
            self.data = Data()
            self.parent = None
            self.children = []
    
        def add_child(self, child):
            self.children.append(child)
            child.parent = self
    
        # NEVER DEFINE LIKE THIS.
        # Only here to illustrate pathological behavior
        def __del__(self):
            del self.data
    
    
    In [3]: a=Node()
    
    In [4]: a.add_child(Node())
    
    In [5]: del a
    
    In [6]: import gc
    
    In [7]: gc.collect()
    Out[7]: 56
    
    In [8]: gc.garbage
    Out[8]:
    [<__main__.Node instance at 0x107a6b200>,
     <__main__.Data instance at 0x107d21638>,
     <__main__.Node instance at 0x107a565f0>,
     <__main__.Data instance at 0x107dd3518>]

    参考:

    https://blog.csdn.net/yueguanghaidao/article/details/11274737

  • 相关阅读:
    有关数据库锁表
    order by 排序的数字异常
    索引建议
    有关文件在浏览器中打开window.open
    vscode 常用快捷键
    jQuery中preventDefault()、stopPropagation()、return false 之间的区别
    理解Linux系统负荷(WDCP系统后台参数之一)
    JavaScript toString() 方法
    1-4:CSS3课程入门之文本新增属性
    1-3:CSS3课程入门之伪类和伪元素
  • 原文地址:https://www.cnblogs.com/shengulong/p/10144466.html
Copyright © 2020-2023  润新知