Python采用的是引用计数机制为主,标记-清理和分代收集两种机制为辅的策略。

1、引用计数

python中一切皆对象,所以python底层计数结构地就可以抽象为:

引用计数结构体{
引用计数;
引用的对象
}

是不是简单明了。现在我们先去考虑一下,什么情况下引用计数+1,什么情况下-1,当引用次数为0时,肯定就是需要进行回收的时刻。

  • 引用计数+1的情况
1、对象被创建时,例如 mark="帅哥"
2、对象被copy引用时,例如 mark2=mark,此时mark引用计数+1
3、对象被作为参数,传入到一个函数中时
4、对象作为一个子元素,存储到容器中时,例如 list=[mark,mark2]
  • 引用计数-1的情况
 
1、对象别名被显式销毁,例如 del mark
2、对象引用被赋予新的对象,例如mark2=mark3,此时mark引用计数-1(对照引用计数+1的情况下的第二点来看)
3、一个函数离开他的作用域,例如函数执行完成,它的引用参数的引用计数-1
4、对象所在容器被销毁,或者从容器中删除。
  • 查看引用计数

实例:

import sys
a = "mark 帅哥"
print(sys.getrefcount(a))
  • 引用计数机制优点
1、简单、直观
2、实时性,只要没有了引用就释放资源。
  • 引用计数机制缺点
 
1、维护引用计数需要消耗一定的资源
2、循环应用时,无法回收。也正是因为这个原因,才需要通过标记-清理和分代收集机制来辅助引用计数机制。

2、标记-清理

由上面内容我们可以知道,引用计数机制有两个缺点,缺点1还可以勉强让人接受,缺点2如果不解决,肯定会引起内存泄露,为了解决这个问题,引入了标记删除。

我们先来看个实例,从实例中领会标记删除:

a=[1,2]#假设此时a的引用为1
b=[3,4]#假设此时b的引用为1
#循环引用
a.append(b)#b的引用+1=2
b.append(a)//a的引用+1=2 假如现在需要删除a,应该如何回收呢?(注意删除a可以使用del a,这样a这个引用就不存在了,但是它指向的对象,在标记删除后还存在,因为还被b使用者) c=[5,6]#假设此时c的引用为1
d=[7,8]#假设此时d的引用为1
#循环引用
c.append(d)#c的引用+1=2
d.append(c)#d的引用+1=2 假如现在需要同时删除c、d,应该如何回收呢?

首先我们应该已经知道,不管上面两种情况的哪一个都无法只通过计数来完成回收,因为随便删除一个变量,它的引用只会-1,变成1,还是大于0,不会回收,为了解决这个问题,开始看标记删除来大展神威吧。

puthon标记删除时通过l两个容器来完成的:死亡容器、存活容器。

首先,我们先来分析情况2,删除c、d
删除后,c的引用为1,d的引用为1,根据引用计数,还无法删除 标记删除第一步:对执行删除操作后的每个引用-1,此时c的引用为0,d的引用为0,把他们都放到死亡容器内。把那些引用仍然大于0的放到存活容器内。 标记删除第二步:遍历存活容器,查看是否有的存活容器引用了死亡容器内的对象,如果有就把该对象(注意是对象,比如0x7f94bb602f80,不是对象的引用)从死亡容器内取出,放到存活容器内。
由于c、d都没有对象引用他们了,所以经过这一步骤,他们还是在死亡组。 标记删除第三部:将死亡组所有对象删除。
这样就完成了对从c、d的删除。

同样道理,我们来分析:只删除a的过程:

标记删除第一步:对执行删除(-1)后的每个引用-1,那么a的引用就是0,b的引用为1,将a放到死亡容器,将b放到存活容器。
标记删除第二步:循环存活容器,发现b引用a,复活a:将a放到存活容器内。
标记删除第三步:删除死亡容器内的所有对象。

综上所说,发现对于循环引用,必须将循环引用的双发对象都删除,才可以被回收。

标记-清理就是这么简单,

最新文章

  1. spring的多个PropertyPlaceholderConfigurer实例装配的问题
  2. My Demo Reels
  3. 获取window窗口大小
  4. Largest Number || LeetCode
  5. 刀哥多线程之gcd-01-sync&async
  6. 无锁编程(五) - RCU(Read-Copy-Update)
  7. HDU 3666 THE MATRIX PROBLEM (差分约束,最短路)
  8. JavaScript 编写线程代码引用Concurrent.Thread.js
  9. CGI与Servlet的区别和联系
  10. Hibernate查询效率对比
  11. bzoj3091
  12. projecteuler之58题Spiral primes
  13. Mac下一个/usr/include失踪
  14. PreparedStatemnet预编译操作数据库的增删改
  15. 用Mockito测试SpringMVC+Hibernate
  16. 利用VGG19实现火灾分类(附tensorflow代码及训练集)
  17. IE8 环境的 JQuery 中的 $.ajax 拒绝访问---解决方案
  18. RPA与AI_新技术能给企业业务流程带来怎样的价值?
  19. 幽灵自建的html5 的模板文件!
  20. python Event_loop(事件循环)

热门文章

  1. 一个数组中两个数的和为N,找出这两个数字的下标
  2. zookeeper及kafka集群搭建
  3. mongodb+nodejs
  4. Symbol Vs String
  5. 让JSON.js完全适应.NET
  6. Access查询时间段 .
  7. emp架构
  8. Android 回调函数的理解,实用简单(回调函数其实是为传递数据)
  9. MVC实战之排球计分(六)—— 使用EF框架,创建Controller,生成数据库。
  10. JVM的永久代会发生垃圾回收吗?