python循环引用检测_python类中显示重写__del__方法引起循环引用的对象无法释放,一种循环引用的检测方法...

这篇博客探讨了Python中的垃圾回收机制,特别是当对象的__del__方法被重写时,如何导致循环引用问题并引发内存泄漏。通过示例展示了如何使用gc模块检测循环引用,特别是`gc.garbage`和`gc.get_referents()`方法,以找出程序中的循环引用链。文章还提醒读者,所有类应继承自object,并建议重写__str__方法以增强打印输出的可读性。
摘要由CSDN通过智能技术生成

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

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

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

注意如下几点:

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

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

代码:

importgcimportpprintimportQueueclassTeacher(object):def __init__(self):

self.name='dan dan'self.Stu=Nonedef __del__(self):print 'test'

def __str__(self):return '"class =%s, name = %s "'%(self.__class__.__name__, self.name)classStudent(object):def __init__(self):

self.name= 'Miss wang'self.Tea=Nonedef __del__(self):print 'des'

def __str__(self):return '"class =%s, name = %s "'%(self.__class__.__name__, self.name)classGraph(object):def __init__(self, name):

self.id= 1self.f= 2.0self.name=name

self.next=None

self.Text=Nonedefset_next(self, next):

self.next=nextdef __str__(self):return '"class =%s, name = %s "'%(self.__class__.__name__, self.name)def __del__(self):print 'destoried'

deftestTeacherStudents():

tea=Teacher()

stu=Student()#set

tea.Stu =stu

stu.Tea=teadeftestGraphs():#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)deffindAllCircleRefs():

gc.collect()for gb ingc.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 notto_process.empty():

chain, next=to_process.get()

chain=chain[:]

chain.append(next)

seen.add(id(next))

allRefs=gc.get_referents(next)for r inallRefs:if not r or isinstance(r, basestring) or isinstance(r, int) or isinstance(r, type) or isinstance(r, float) orisinstance(r, tuple):#Ignore strings and classes

pass

elif id(r) inseen:print

print 'Found a cycle to %s:' %rfor i, link inenumerate(chain):print '%d:' %i, linkelse:

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>, 'name': 'dan dan'}2: "class =Student, name = Miss wang"

3: {'Tea': <__main__.teacher object at>, 'name': 'Miss wang'}

Found a cycle to"class =Student, name = Miss wang":

0:"class =Student, name = Miss wang"

1: {'Tea': <__main__.teacher object at>, 'name': 'Miss wang'}2: "class =Teacher, name = dan dan"

3: {'Stu': <__main__.student object at>, 'name': 'dan dan'}

Found a cycle to"class =Graph, name = one":

0:"class =Graph, name = one"

1: {'Text': None, 'next': <__main__.graph object at>, 'id': 1, 'name': 'one', 'f': 2.0}2: "class =Graph, name = two"

3: {'Text': None, 'next': <__main__.graph object at>, 'id': 1, 'name': 'two', 'f': 2.0}4: "class =Graph, name = three"

5: {'Text': None, 'next': <__main__.graph object at>, '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>, 'id': 1, 'name': 'two', 'f': 2.0}2: "class =Graph, name = three"

3: {'Text': None, 'next': <__main__.graph object at>, 'id': 1, 'name': 'three', 'f': 2.0}4: "class =Graph, name = one"

5: {'Text': None, 'next': <__main__.graph object at>, '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>, 'id': 1, 'name': 'three', 'f': 2.0}2: "class =Graph, name = one"

3: {'Text': None, 'next': <__main__.graph object at>, 'id': 1, 'name': 'one', 'f': 2.0}4: "class =Graph, name = two"

5: {'Text': None, 'next': <__main__.graph object at>, 'id': 1, 'name': 'two', 'f': 2.0}

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值