如果你写过C和C++,你一定知道程序中的内存管理是非常关键的,一不小心就有可能发生内存泄漏。但是我们在编写Python时似乎从不关心内存处理。为什么这么酷?在你酷炫的背后,Python其实在默默地帮你管理。让我告诉你如何实现它。1.引用计数在Python中,引用计数技术用于实现内存管理。一个对象创建后,有一个变量指向它,也就是说它的引用计数为1,如果以后还有其他变量指向它,引用计数就会相应增加。如果某个变量不再对该对象执行,则该对象的引用计数减1。如果一个对象没有任何变量指向它,即引用计数为0,那么该对象将被回收Python。示例代码如下:classPerson(object):def__init__(self,name):self.name=namedef__del__(self):print('%sexecuteddelfunction'%self.name)whileTrue:p1=Person('p1')p2=Person('p2')delp1delp2a=input('test:')可以看出两个对象的del函数都执行了。2.循环引用虽然引用计数技术可以在一定程度上解决内存管理的问题。但是还有一个问题无法解决,就是循环引用。比如现在有两个对象a和b,a指向b,b指向a,那么这两个对象的引用计数永远不会为0,也就是永远不会被回收。看下面的例子:classPerson(object):def__init__(self,name):self.name=namedef__del__(self):print('%sexecutedthedelfunction'%self.name)whileTrue:p1=Person('p1')p2=Person('p2')#循环引用后,永远不会被释放p1.next=p2p2.prev=p1delp1delp2a=input('test:')你可以看,del函数不会运行,因为循环引用导致两个对象没有被释放。3.标记清除和分代回收在Python程序中,每创建一个新的对象,这个对象都会链接到一个叫做零代的链表(当然这个链表是Python内部的,Python开发者没有不能被访问)。比如现在你在程序中创建了四个Person对象,分别命名为p1、p2、p3、p4,然后p1和p2相互引用,让p3和p4的引用计数为2。示例代码为如下:importsysclassPerson(object):def__init__(self,name):self.name=nameself.next=Noneself.prev=Nonep1=Person('p1')p2=Person('p2')p3=Person('p3')p4=Person('p4')p1.next=p2p2.prev=p1temp1=p3temp2=p4print(sys.getrefcount(p1))print(sys.getrefcount(p2))print(sys.getrefcount(p3))print(sys.getrefcount(p4))上面的代码实际上会将p1和p2以及p3和p4挂在一个叫做零代的链表中。示例图如下:我们可以看到此时p1引用了p2,p2引用了p1,所以这两个对象产生了循环引用。即使我后面删除了delp1和delp2,这两个对象也不会被释放。所以这个时候Python启用了一种新的垃圾回收机制。如果创建的对象减去释放的对象的总和达到某个值(某个阈值),那么Python会遍历零代链表,找到那些有相互引用的对象,将这些对象的引用计数减1,如果引用计数值为0,则表示可以释放对象,比如上面的p1和p2,那么p1和p2就会被释放。接下来,将没有释放的对象移动到一个新的链表中,称为第一代链表。当零代链表的清理次数达到一定阈值后,Python会遍历第一代链表,将那些没有被释放的对象移到第二代链表中。同样的原理,如果第一代链表的清理次数达到一定阈值,Python会遍历第二代链表,回收垃圾对象。四、弱代假说让我们看一下代垃圾收集算法的核心行为:垃圾收集器会更频繁地处理新对象。新对象是你的程序刚刚创建的对象,新对象是经过几个时间段后仍然存在的对象。Python在对象从第0代移动到第1代,或者从第1代移动到第2代时,会提升一个对象。为什么要这样做?该算法的根源来自弱世代假设(weakgenerationalhypothesis)。这个假设包含两个观点:首先,年轻的对象通常会很快死亡,而老的对象可能会活得更久。现在假设我在Python中创建了一个新对象:根据假设,我的代码可能只会在短时间内使用ABC。这个对象可能只是一个方法的中间结果,当方法返回时这个对象将变成垃圾。大多数新对象都像这样很快变成垃圾。然而,有时程序会创建一些非常重要的、长期存在的对象——例如Web应用程序中的会话变量或配置项。通过频繁地处理零代列表中的新对象,Python的垃圾收集器将把时间花在一个更有意义的地方:它处理那些可能很快就会变成垃圾的新对象。同时,只有极少数情况下,当满足阈值条件时,收集器会返回处理那些旧变量。文渊网络仅供学习使用,如有侵权,请联系删除。我的公众号【Python圈】汇集了优质的技术文章和经验总结。学习Python的路上肯定会遇到困难,不要慌张,我这里有一套学习资料,包括40+电子书,600+教学视频,涉及Python基础、爬虫、框架、数据分析、机学习等等,别怕学不会!还有学习交流群,一起学习进步~
