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


     在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
        "
    begin collect..."
        _unreachable = gc.collect()
        print("unreachable object num:{}".format(_unreachable))
        print("garbage object num:{}".format(len(gc.garbage)))
    
    
    if __name__ == "__main__":
        test_gcleak()

    结果

    C:Python35python.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
        "
    begin collect..."
        _unreachable = gc.collect()
        print("unreachable object num:{}".format(_unreachable))
        print("garbage object num:{}".format(len(gc.garbage)))
    
    
    if __name__ == "__main__":
        test_gcleak()

    结果是:

    C:Python35python.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
        "
    begin 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
        "
    begin 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

  • 相关阅读:
    详解vue静态资源打包中的坑与解决方案
    vue项目构建实战基础知识:SPA理解/RESTful接口介绍/static目录配置/axios封装/打包时map文件去除
    axios踩坑记录+拦截器使用+vue cli代理跨域proxy+webpack打包部署到服务器
    vue-cli项目开发/生产环境代理实现跨域请求+webpack配置开发/生产环境的接口地址
    vue中watch的用法总结以及报错处理Error in callback for watcher "checkList"
    Vue侦听器watch
    ES6 import 引用文件夹/目录及其处理过程
    Nginx部署前端代码实现前后端分离
    使用XmlInclude解决WebService调用时无法识别子类的异常
    WebServices中Xml的序列化
  • 原文地址:https://www.cnblogs.com/aomi/p/7569545.html
Copyright © 2020-2023  润新知