Python垃圾回收之循环引用

来源:互联网 发布:知乎量子纠缠与超光速 编辑:程序博客网 时间:2024/05/15 18:32

什么情况存在内存泄露

  • python引用计数 + 分代收集和标记清除(处理循环引用),进行垃圾回收,但如下两种情况依旧存在内存泄露:
  • 第一是对象被另一个生命周期特别长(如全局变量)的对象所引用
  • 第二是循环引用中的对象定义了__del__函数,简而言之,循环引用中Python无法判断析构对象的顺序,无法释放

相关术语

  • reachable/collectable(unreachable/uncollectable)
  • reachable是针对python对象而言,如果从根集(root)能到找到对象,那么这个对象就是reachable,与之相反就是unreachable,unreachable只存在于循环引用中的对象,Python的gc模块就是针对unreachable对象
  • collectable是针对unreachable对象而言,如果这种对象能被回收,是collectable,如果不能被回收,即循环引用中的对象定义了__del__, 那么就是uncollectable。 即unreachable (循环引用)分成 collectable和ubcollectable(__del__

GC模块

This module provides access to the garbage collector for reference cycles.enable() -- Enable automatic garbage collection.disable() -- Disable automatic garbage collection.isenabled() -- Returns true if automatic collection is enabled.collect() -- Do a full collection right now. Tg

gc.set_debug(flags)
gc.DEBUG_COLLETABLE: 打印可以被垃圾回收器回收的对象
gc.DEBUG_UNCOLLETABLE: 打印无法被垃圾回收器回收的对象,即定义了__del__的对象
gc.DEBUG_SAVEALL:所有的unreachable对象都将加入gc.garbage返回的列表
gc.garbage: 返回是unreachable对象,且不能被回收的的对象,如果设置SAVEALL,所有unreachable都加入此列表

A list of objects which the collector found to be unreachable but could not be freed (uncollectable objects). Starting with Python 3.4, this list should be empty most of the time, except when using instances of C extension types with a non-NULL tp_del slot.

禁用GC

只要能手动解决循环引用,就可以禁止GC模块来提高效率,因为GC适用于循环引用的垃圾回收机制。 如果可以确定代码没有循环引用,那么可以禁用GC模块

特殊说明(PEP442)

python3.4开始已经可以自动处理带有__del__方法的循环引用,也不会发生内存泄露了

import gcclass Foo(object):    def __init__(self):        self.bar = None        print('foo init')    def __del__(self):        print("foo del")class Bar(object):    def __init__(self):        self.foo = None        print('bar init')    def __del__(self):        print('bar del')def collect_and_show_garbage():    print("Collecting...")    n = gc.collect()    print("unreachable objects:", n)    print(gc.garbage)def func():    foo = Foo()    bar = Bar()    foo.bar = bar    bar.foo = foo# gc.set_debug(gc.DEBUG_COLLECTABLE | gc.DEBUG_UNCOLLECTABLE)func()collect_and_show_garbage()

python2.7
foo init
bar init
Collecting…
(‘unreachable objects:’, 4)
[<main.Foo object at 0x101235550>, <main.Bar object at 0x1012355d0>]

python3.6
foo init
bar init
Collecting…
foo del
bar del
unreachable objects: 4
[]

gc.collect() 返回unreachable的数目,所以无论2.7还是3.6都一样,但、3.6中可以处理循环引用且带有__del__的情况,所以gc.garbage为空,当然如果没有__del__方法,2.7中gc.garbage也是空

原创粉丝点击