zoukankan      html  css  js  c++  java
  • python类中显示重写__del__方法引起循环引用的对象无法释放,一种循环引用的检测方法

    通常情况下,python的gc 垃圾回收机制,有一套算法,可以用来回收循环引用的对象,避免内存泄露。

    不过,有个例外的情况:显示重写了__del__方法。此时gc就无法释放资源,因为循环引用导致了引用计数器不可能为0。需要打破这种循环引用关系,才能释放资源。这就催生了招到一种,能去找出我们的程序代码中,存在的循环引用的关系。

      gc中gc.garbage记录了所有不可回收的垃圾。gc.get_referents方法可以用来获得所有引用到该对象的资源。代码如下:

    注意如下几点:

    1. 所有的class应该继承与object或者,都有一个共同的基类object,这也是一个好的设计习惯。在该检测循环引用方法中,如果没有继承object,则发现会有死循环问题。而且检测的输出结果也不正确。()

    2.为了保证class的print结果具有可参考性,可以重写其__str__()方法,输出一些有用信息。

    代码:

    import gc
    import pprint
    import Queue
    
    class Teacher(object):
        def __init__(self):
            self.name ='dan dan'
            self.Stu = None
            
        def __del__(self):
            print 'test'
         
        def __str__(self):
            return '"class =%s, name = %s "'%(self.__class__.__name__, self.name)
            
    class Student(object):
        def __init__(self):
            self.name = 'Miss wang'
            self.Tea = None
        
        def __del__(self):
            print 'des'    
        
        def __str__(self):
            return '"class =%s, name = %s "'%(self.__class__.__name__, self.name)
    
    class Graph(object):
        def __init__(self, name):
            self.id = 1
            self.f = 2.0
            self.name = name
            self.next = None
            self.Text = None
        def set_next(self, next):
            self.next = next
        
        def __str__(self):
            return '"class =%s, name = %s "'%(self.__class__.__name__, self.name)
            
        def __del__(self):
            print 'destoried'
            
    def testTeacherStudents():
        tea = Teacher()
        stu = Student()
        
        #set
        tea.Stu = stu
        stu.Tea = tea  
        
    def testGraphs():
        # Construct a graph cycle
        one = Graph('one')
        two = Graph('two')
        three = Graph('three')
        one.set_next(two)
        two.set_next(three)
        three.set_next(one)
    
    def findAllCircleRefs():
        gc.collect()
        for gb in gc.garbage:    
            seen = set()
            to_process = Queue.Queue()
            # Start with an empty object chain and Graph three.
            to_process.put( ([], gb) )
            
            # Look for cycles, building the object chain for each object we find
            # in the queue so we can print the full cycle when we're done.
            while not to_process.empty():
                chain, next = to_process.get()
                chain = chain[:]
                chain.append(next)
                seen.add(id(next))
                allRefs = gc.get_referents(next)
                for r in allRefs:
                    if not r or isinstance(r, basestring) or isinstance(r, int) or isinstance(r, type) or isinstance(r, float) or isinstance(r, tuple):
                        # Ignore strings and classes
                        pass
                    elif id(r) in seen:
                        print
                        print 'Found a cycle to %s:' % r
                        for i, link in enumerate(chain):
                            print '  %d: ' % i, link
                    else:
                        to_process.put( (chain, r) )
    
    testTeacherStudents()
    testGraphs()
    findAllCircleRefs()

    输出结果:

    Found a cycle to "class =Teacher, name = dan dan ":
      0:  "class =Teacher, name = dan dan "
      1:  {'Stu': <__main__.Student object at 0x01BCF6B0>, 'name': 'dan dan'}
      2:  "class =Student, name = Miss wang "
      3:  {'Tea': <__main__.Teacher object at 0x01BCF670>, 'name': 'Miss wang'}
    
    Found a cycle to "class =Student, name = Miss wang ":
      0:  "class =Student, name = Miss wang "
      1:  {'Tea': <__main__.Teacher object at 0x01BCF670>, 'name': 'Miss wang'}
      2:  "class =Teacher, name = dan dan "
      3:  {'Stu': <__main__.Student object at 0x01BCF6B0>, 'name': 'dan dan'}
    
    Found a cycle to "class =Graph, name = one ":
      0:  "class =Graph, name = one "
      1:  {'Text': None, 'next': <__main__.Graph object at 0x01BCFE70>, 'id': 1, 'name': 'one', 'f': 2.0}
      2:  "class =Graph, name = two "
      3:  {'Text': None, 'next': <__main__.Graph object at 0x01C0EFD0>, 'id': 1, 'name': 'two', 'f': 2.0}
      4:  "class =Graph, name = three "
      5:  {'Text': None, 'next': <__main__.Graph object at 0x01BCFD70>, 'id': 1, 'name': 'three', 'f': 2.0}
    
    Found a cycle to "class =Graph, name = two ":
      0:  "class =Graph, name = two "
      1:  {'Text': None, 'next': <__main__.Graph object at 0x01C0EFD0>, 'id': 1, 'name': 'two', 'f': 2.0}
      2:  "class =Graph, name = three "
      3:  {'Text': None, 'next': <__main__.Graph object at 0x01BCFD70>, 'id': 1, 'name': 'three', 'f': 2.0}
      4:  "class =Graph, name = one "
      5:  {'Text': None, 'next': <__main__.Graph object at 0x01BCFE70>, 'id': 1, 'name': 'one', 'f': 2.0}
    
    Found a cycle to "class =Graph, name = three ":
      0:  "class =Graph, name = three "
      1:  {'Text': None, 'next': <__main__.Graph object at 0x01BCFD70>, 'id': 1, 'name': 'three', 'f': 2.0}
      2:  "class =Graph, name = one "
      3:  {'Text': None, 'next': <__main__.Graph object at 0x01BCFE70>, 'id': 1, 'name': 'one', 'f': 2.0}
      4:  "class =Graph, name = two "
      5:  {'Text': None, 'next': <__main__.Graph object at 0x01C0EFD0>, 'id': 1, 'name': 'two', 'f': 2.0}

    由上面的输出结果,可以看到Teach类和student类产生了循环引用。

    graph的one,two和three之间产生了一个引用环。

    重写了__del__方法及这些循环引用,导致了循环引用计数器无法归零,gc无法回收这些资源,导致垃圾产生,内存泄露。

  • 相关阅读:
    经典的Java基础面试题集锦
    2016春招Android开发实习生(网易传媒)笔试
    十三、集合点和事务
    十一、LoadRunner组成和工作原理
    Java+selenium之WebDriver常见特殊情况如iframe/弹窗处理(四)
    修改jar包内容并打包上传到私服
    Information:java: Multiple encodings set for module chunk platf "GBK" will be used by compile
    十、创建、运行和监控测试场景
    在gitlab新建分支,IDEA切换时找不到的解决办法
    Git 代码撤销、回滚到任意版本(当误提代码到本地或master分支时)
  • 原文地址:https://www.cnblogs.com/ankier/p/3000760.html
Copyright © 2011-2022 走看看