python采用的是引用计数机制为主,隔代回收机制为辅的策略。
引用计数
- 引用计数机制的优点:
- 简单
- 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
- 引用计数机制的缺点:
- 维护引用计数消耗资源
- 无法解决循环引用的问题(致命)
隔代回收
python 利用隔代回收机制,解决了循环引用问题。
他山之石:ruby 标记-清除
ruby中采用的是标记清除机制。
ruby使用链表来预分配对象,早在代码开始执行前,Ruby就提前创建了成百上千个对象,并把它们串在链表上,名曰:可用列表。每当我们创建一个对象,就从可用列表里分配一个位置。
随着我们创建越来越多的对象,Ruby会持续寻可用列表里取预创建对象给我们。因此,可用列表会逐渐变短,当可用列表最终被用光光时,Ruby便祭出"地球停转垃圾回收大法"。首先Ruby把程序停下来,之后Ruby轮询所有指针,标记存活的对象,剩下的未被标记的对象只能是垃圾,清理垃圾并将它们归位到可用列表中。
标记-删除 vs. 引用计数
乍一看,Python的GC算法貌似远胜于Ruby的:宁舍洁宇而居秽室乎?为什么Ruby宁愿定期强制程序停止运行,也不使用Python的算法呢?
然而,引用计数并不像第一眼看上去那样简单。有许多原因使得不许多语言不像Python这样使用引用计数GC算法:
首先,它不好实现。Python不得不在每个对象内部留一些空间来处理引用数。这样付出了一小点儿空间上的代价。但更糟糕的是,每个简单的操作(像修改变量或引用)都会变成一个更复杂的操作,因为Python需要增加一个计数,减少另一个,还可能释放对象。
第二点,它相对较慢。虽然Python随着程序执行GC很稳健(一把脏碟子放在洗碗盆里就开始洗啦),但这并不一定更快。Python不停地更新着众多引用数值。特别是当你不再使用一个大数据结构的时候,比如一个包含很多元素的列表,Python可能必须一次性释放大量对象。减少引用数就成了一项复杂的递归过程了。
最后,它不是总奏效的。引用计数不能处理环形数据结构--也就是含有循环引用的数据结构。
查看一个对象的引用计数
import sys
a = "hello world"
sys.getrefcount(a)
可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1
网友评论