python的垃圾回收机制是怎么实现的

  在C语言时代程序员要负责内存的申请和释放,虽然这样的程序可以对资源进行精细的控制、但是它也有它的问题、这就要求程序员

  要写许多与业务逻辑无关的内容在代码里面;更大的问题是程序员有可能忘记了释放自己申请的资源。如果一个程序总是申请资源而

  不主动把资源释放给操作系统、那么操作系统有再多的资源也不够给程序败的。

  所以呢! C语言不但对程序员的能力有比较高的要求,还要它比较细心才行;我之前就遇到过一个家公司他们的C#代码有问题,Task

  对象应该在用完之后要close的、可是程序员并没有这样做,这使得主机运行几天内存就不足了;然后他们就每天凌晨没人用的时候重

  启一下window-server。  

  与大多数语言一样python的垃圾的回收也是基于引用计数来实现的;也就是说你用python创建的每一个对象python解释器都会在后台

  默默的给你记住有多少个变量名引用了你创建的对象、当它发现有0个变量名引用了你创建的对象之后、解释器就会把对象给释放掉。

1、如果确定一个对象有多少个变量名引用了它

  sys模块的getrefcount函数可以返回给定对象的引用数量

  1. >>> i = 65535
  2. >>> sys.getrefcount(i)
  3. 2
  4. >>>

  为什么返回的是2而不是 1 、根据官方文档的说法是getrefcount函数的内部也引用传入的对象、所以i对象在两处被引用了、所以返回

  了2。值得一提的是,这还并不是关于gerefcount的全部,请看下面的代码

  1. >>> j = 1
  2. >>> sys.getrefcount(j)
  3. 733

  这时返回733的原因是由于官方对性能的一个优化造成的,像“1”这样的值是非常、常用的,所以python并没有为这733处用到1的地方都

  创建一个“1”而是让他们共用同一个“1”所以对于一些比较特别的getrefcount的返回看起一就大了去了。

2、什么是弱引用

  要说清楚弱引用还要通过一般的引用说起、如果你有其它oop语言的经历你可能会知道“装箱”,“拆箱”这一对名词,在python中一些都

  是对象并没有谁是特殊的,也就是说不存在“装箱”,“拆箱”的概念;对于赋值语句最正确的理解是在对象上粘标签,用下面例子来说明

  这个

  1. >>> i = 65535
  2. >>> j = i
  3. >>>

  第一行说的是创建一个对象(int类型)它的值是65535、并给对象粘上标签“i”、在这之后就可以通过“i”引用65535这个值了;

  第二行是在i所引用的对象上再粘一个标签,这个新标签的名字叫“j”;应该和你想的一样由于65535这个对象分别被“i,j”引用

  了,所以sys.getrefcount(i)应该要返回“3”

  1. >>> i = 65535
  2. >>> j = i
  3. >>> sys.getrefcount(j)
  4. 3

  弱引用就是虽然在对象上多粘了一个标签,但是对象的引用计数器并不会增长。感觉文字不足以表达,还是直接上代码吧;

  1. >>> from weakref import ref
  2. >>> class Node(object):
  3. ... pass
  4. ...
  5. >>> a = Node()
  6. >>> sys.getrefcount(a)
  7. 2
  8. >>> b = a
  9. >>> sys.getrefcount(a)
  10. 3
  11. >>> c = ref(a)
  12. >>> sys.getrefcount(a)
  13. 3

  可以看到通过ref函数转一道手后 c 这个标签虽然粘上去了,但是并不会引起引用计数器的增长。

3、我们通过什么方式可以观察到垃圾回收

  对象的__del__这个魔术方法就是在垃圾回收时调用的,也就是说我们只要重写这个方法、并在方法内打印一定的输出我们就可以做到

  垃圾回收的肉眼可见了。

  1. >>> class Node():
  2. ... def __init__(self,value):
  3. ... self.value=value
  4. ... def __del__(self):
  5. ... print('this is __del__'.format(self.value))
  6. ...
  7. >>> n = Node(123)
  8. >>> del n
  9. this is __del__
  10.  
  11. >>> n = Node(456)
  12. >>> n = None
  13. this is __del__

  可以看到有两种方法可以触发垃圾回收程序、1):显示的del一个对象,2):当一个对象的引用计数器为零时 。这两种情况任何一种发

  生后对象就会被标记为“可回收”状态,垃圾回收器会基于一定的算法对它们进行垃圾回收。

4、谈谈垃圾回收不起作用的情况

  正常情况下没有垃圾回收不起作用的情况、通常垃圾得不到回收是因为我们的代码逻辑上有问题;这个问题使得,即使对于那些

  不使用的对象它的引用计数器也不为 0 ,这就使得垃圾回收不起作用了。这种问题目前我遇到过的情况就是因为“环形”的数据

  结构引起的、可以看一下的例子

  1. >>> class Node(object):
  2. ... def __init__(self,value,child=None):
  3. ... self.value=value
  4. ... self.child=child
  5. ... def set_child(self,child):
  6. ... self.child=child
  7. ... def __del__(self):
  8. ... print("Node.__del__ {0}".format(self.value))
  9.  
  10. >>> child = Node('child')
  11. >>> root.set_child(child)
  12. >>> child.set_child(root)
  13. >>> del child
  14. >>> del root
  15. >>>
  16. >>>
  17. >>>

  可以看到 del child 和 del root 都没有能触发垃圾回收、问题就在于对象的引用计数器并不为零;拿root来说吧,它还被child.child这个名字引用着

  所以引用计数器并不认为child是一个可以回收的对象,所以我们并没有看到理想中的__del__魔术方法的执行。  

5、通过弱引用来修复bug

  1. from time import sleep
  2. from weakref import ref
  3. from sys import getrefcount
  4.  
  5. class Node(object):
  6. ... def __init__(self,value,child=None):
  7. ... self.value=value
  8. ... self.child=child
  9. ... def set_child(self,child):
  10. ... self.child=ref(child) #self.child以弱引用方式实现
  11. ... def __del__(self):
  12. ... print("Node.__del__ {0}".format(self.value))
  13.  
  14. >>> root = Node('root')
  15. >>> child = Node('child')
  16. >>> root.set_child(child)
  17. >>> child.set_child(root)
  18. >>> print(getrefcount(root))
  19. 2
  20. >>> print(getrefcount(child))
  21. 2
  22. >>> del child
  23. Node.__del__ child
  24. >>> del root
  25. Node.__del__ root
  26. >>>
  27. >>>
  28. >>>

      

  

  

 

----

谈一谈python的垃圾回收机制的更多相关文章

  1. 详解python的垃圾回收机制

    python的垃圾回收机制 一.引子 我们定义变量会申请内存空间来存放变量的值,而内存的容量是有限的,当一个变量值没有用了(简称垃圾)就应该将其占用的内存空间给回收掉,而变量名是访问到变量值的唯一方式 ...

  2. python的垃圾回收机制和析构函数__del__

    析构函数__del__定义:在类里定义,如果不定义,Python 会在后台提供默认析构函数. 析构函数__del__调用: A.使用del 显式的调用析构函数删除对象时:del对象名: class F ...

  3. python之垃圾回收机制

    一.前言 Python 是一门高级语言,使用起来类似于自然语言,开发的时候自然十分方便快捷,原因是Python在背后为我们默默做了很多事情,其中一件就是垃圾回收,来解决内存管理,内存泄漏的问题. 内存 ...

  4. Python核心技术与实战——二十|Python的垃圾回收机制

    今天要讲的是Python的垃圾回收机制 众所周知,我们现在的计算机都是图灵架构.图灵架构的本质,就是一条无限长的纸带,对应着我们的存储器.随着寄存器.异失性存储器(内存)和永久性存储器(硬盘)的出现, ...

  5. Python的 垃圾回收机制

    垃圾回收 1. 小整数对象池 整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间. Python 对小整数的定义是 [-5, 257) 这些整 ...

  6. 浅谈V8引擎中的垃圾回收机制

    最近在看<深入浅出nodejs>关于V8垃圾回收机制的章节,转自:http://blog.segmentfault.com/skyinlayer/1190000000440270 这篇文章 ...

  7. Python的垃圾回收机制

    Python的GC模块主要运用了“引用计数”(reference counting)来跟踪和回收垃圾.在引用计数的基础上,还可以通过“标记-清除”(mark and sweep)解决容器对象可能产生的 ...

  8. 【Python】 垃圾回收机制和gc模块

    垃圾回收机制和gc模块 Py的一个大好处,就是灵活的变量声明和动态变量类型.虽然这使得学习py起来非常方便快捷,但是同时也带来了py在性能上的一些不足.其中相关内存比较主要的一点就是py不会对已经销毁 ...

  9. Python的垃圾回收机制(引用计数+标记清除+分代回收)

    一.写在前面: 我们都知道Python一种面向对象的脚本语言,对象是Python中非常重要的一个概念.在Python中数字是对象,字符串是对象,任何事物都是对象,而它们的核心就是一个结构体--PyOb ...

随机推荐

  1. Warning: Divide by zero.

    问题:如标题 解决方案:分母加上+eps   参考自:http://www.ilovematlab.cn/thread-43128-1-1.html

  2. JEECG中的validform验证ajaxurl的使用方法

    validform验证是一种非常方便的,实用的验证方式 对于需要验证后台数据的,validform是一个非常明智的选择 validform的ajaxurl属性能够完美的实现:当输入完成某一输入框,就会 ...

  3. 算法笔记_202:第三届蓝桥杯软件类决赛真题(Java高职)

    目录 1 填算式 2 提取子串 3 机器人行走 4 地址格式转换 5 排日程   前言:以下代码仅供参考,若有错误欢迎指正哦~ 1 填算式 [结果填空] (满分11分) 看这个算式: ☆☆☆ + ☆☆ ...

  4. How do I fix a “Unknown configuration key `foreign-architecture' found in your `dpkg' configuration files.” error?

    My /etc/dpkg/dpkg.cfg.d/multiarch contained: foreign-architecture i386 I deleted the file. I then is ...

  5. Leveldb 使用说明文档

    Leveldb 使用说明文档 原作者:Jeff Dean, Sanjay Ghemawat 翻译:乌合之众solym@sohu.com 英文原文地址https://rawgit.com/google/ ...

  6. Ubuntu16.04 Arduino UNO R3开发板

    使用的是国内改过的版本, usb芯片换成了ch341, 晶振不是原版的16MHz而是12MHz, 杜邦线孔布局和原版一致. 设备连接 在Ubuntu16.04下不需要驱动, 能直接认出ch341设备 ...

  7. 编程算法 - 迷宫的最短路径 代码(C++)

    迷宫的最短路径 代码(C++) 本文地址: http://blog.csdn.net/caroline_wendy 题目: 给定一个大小为N*M的迷宫. 迷宫由通道和墙壁组成, 每一步能够向邻接的上下 ...

  8. JavaScript 数组(Array)对象

    Array 对象 Array 对象用于在单个的变量中存储多个值. 创建 Array 对象的语法: new Array(); new Array(size); new Array(element0, e ...

  9. 【解决问题】failed: java.lang.RuntimeException: org.openqa.selenium.WebDriverException: Unexpected error launching Internet Explorer.

    failed: java.lang.RuntimeException: org.openqa.selenium.WebDriverException: Unexpected error launchi ...

  10. libev ev_init分析

    /* these may evaluate ev multiple times, and the other arguments at most once */ /* either use ev_in ...