代码改变世界

Python垃圾回收机制:gc模块(zz)

2017-09-21 17:03  很大很老实  阅读(469)  评论(0编辑  收藏  举报

 在Python中,为了解决内存泄露问题,采用了对象引用计数,并基于引用计数实现自动垃圾回

    由于Python 有了自动垃圾回收功能,就造成了不少初学者误认为不必再受内存泄漏的骚扰了。但如果仔细查看一下Python文档对 __del__() 函数的描述,就知道这种好日子里也是有阴云的。下面摘抄一点文档内容如下:

Some common situations that may prevent the reference count of an object from going to zero include: circular references between objects (e.g., a doubly-linked list or a tree data structure with parent and child pointers); a reference to the object on the stack frame of a function that caught an exception (the traceback stored in sys.exc_traceback keeps the stack frame alive); or a reference to the object on the stack frame that raised an unhandled exception in interactive mode (the traceback stored in sys.last_traceback keeps the stack frame alive).

  可见, __del__() 函数的对象间的循环引用是导致内存泄漏的主凶。但没有__del__()函数的对象间的循环引用是可以被垃圾回收器回收掉的。

    如何知道一个对象是否内存泄露掉了呢?

    可以通过Python的扩展模块gc来查看不能回收掉的对象的详细信息。

 

例1:没有出现内存泄露的

import gc
import sys

class CGcLeak(object):
    def __init__(self):
        self._text='#'*10

    def __del__(self):
        pass


def make_circle_ref():
    _gcleak=CGcLeak()
    
    print("_gcleak ref count0:{}".format(sys.getrefcount(_gcleak)))
    del _gcleak

    try:
        print("_gcleak ref count:{}".format(sys.getrefcount(_gcleak)))
    except UnboundLocalError:
        print("_gcleak is invalid!")

def test_gcleak():
    gc.enable()

    print("begin leak test...")
    make_circle_ref()

    print
    "\nbegin collect..."
    _unreachable = gc.collect()
    print("unreachable object num:{}".format(_unreachable))
    print("garbage object num:{}".format(len(gc.garbage)))


if __name__ == "__main__":
    test_gcleak()

结果

C:\Python35\python.exe C:/wcf/django/ftest/ftest.py
begin leak test...
_gcleak ref count0:2
_gcleak is invalid!
unreachable object num:0
garbage object num:0

Process finished with exit code 0

例2:对自己的循环引用造成内存泄露

import gc
import sys

class CGcLeak(object):
    def __init__(self):
        self._text='#'*10

    def __del__(self):
        pass


def make_circle_ref():
    _gcleak=CGcLeak()
    _gcleak._self = _gcleak
    print("_gcleak ref count0:{}".format(sys.getrefcount(_gcleak)))
    del _gcleak

    try:
        print("_gcleak ref count:{}".format(sys.getrefcount(_gcleak)))
    except UnboundLocalError:
        print("_gcleak is invalid!")

def test_gcleak():
    gc.enable()

    print("begin leak test...")
    make_circle_ref()

    print
    "\nbegin collect..."
    _unreachable = gc.collect()
    print("unreachable object num:{}".format(_unreachable))
    print("garbage object num:{}".format(len(gc.garbage)))


if __name__ == "__main__":
    test_gcleak()

结果是:

C:\Python35\python.exe C:/wcf/django/ftest/ftest.py
begin leak test...
_gcleak ref count0:3
_gcleak is invalid!
unreachable object num:2
garbage object num:0

Process finished with exit code 0

例3:多个对象间的循环引用造成内存泄露 

import gc
import sys

class CGcLeakA(object):
    def __init__(self):
        self._text='#'*10

    def __del__(self):
        pass

class CGcLeakB(object):
    def __init__(self):
        self._text='$'*10

    def __del__(self):
        pass


def make_circle_ref():
    _a=CGcLeakA()
    _b = CGcLeakB()
    _a.s=_b
    _b.s=_a

    print("ref count0:_a is {},_b is {}".format(sys.getrefcount(_a),sys.getrefcount(_a)))
    del _a
    del _b


    try:
        print("ref count:_a is {}".format(sys.getrefcount(_a)))
    except UnboundLocalError:
        print("_a is invalid!")

def test_gcleak():
    gc.enable()

    print("begin leak test...")
    make_circle_ref()

    print
    "\nbegin collect..."
    _unreachable = gc.collect()
    print("unreachable object num:{}".format(_unreachable))
    print("garbage object num:{}".format(len(gc.garbage)))


if __name__ == "__main__":
    test_gcleak()

运行结果:

import gc
import sys

class CGcLeakA(object):
    def __init__(self):
        self._text='#'*10

    def __del__(self):
        pass

class CGcLeakB(object):
    def __init__(self):
        self._text='$'*10

    def __del__(self):
        pass


def make_circle_ref():
    _a=CGcLeakA()
    _b = CGcLeakB()
    _a.s=_b
    _b.s=_a

    print("ref count0:_a is {},_b is {}".format(sys.getrefcount(_a),sys.getrefcount(_a)))
    del _a
    del _b


    try:
        print("ref count:_a is {}".format(sys.getrefcount(_a)))
    except UnboundLocalError:
        print("_a is invalid!")

def test_gcleak():
    gc.enable()

    print("begin leak test...")
    make_circle_ref()

    print
    "\nbegin collect..."
    _unreachable = gc.collect()
    print("unreachable object num:{}".format(_unreachable))
    print("garbage object num:{}".format(len(gc.garbage)))


if __name__ == "__main__":
    test_gcleak()

 

转自:

http://www.cnblogs.com/kaituorensheng/p/4449457.html