Python垃圾回收机制-1

举报
清风Python 发表于 2018/05/14 09:49:10 2018/05/14
【摘要】 python 垃圾回收引用计数器一个对象,会记录着自身被引用的个数 每增加一个引用,这个对象的引用计数会自动+1 每减少一个引用,这个对象的引用计数会自动-1查看引用计数import sys sys.getrefcount(对象)关于getrefcount:getrefcount(object) -> integer Return the reference count of object....

python 垃圾回收

引用计数器

一个对象,会记录着自身被引用的个数 
每增加一个引用,这个对象的引用计数会自动+1 
每减少一个引用,这个对象的引用计数会自动-1

查看引用计数

import sys sys.getrefcount(对象)

关于getrefcount:

getrefcount(object) -> integer 
Return the reference count of object. The count returned is generally 
one higher than you might expect, because it includes the (temporary) 
reference as an argument to getrefcount().

注意下加粗的两个地方:
  1. 需要获取一个对象的引用次数,而非一个类

  2. 由于你通过getrefcount引用了这个对象,所以总引用次数要比实际多1

来个例子看看吧
import sysclass Uranus:
    passu1 = Uranus()
print(sys.getrefcount(u1)-1) # 1u3 = u2 = u1
print(sys.getrefcount(u1)-1) # 3del u3
print(sys.getrefcount(u1)-1) # 2del u2
print(sys.getrefcount(u1)-1) # 1del u1
print(sys.getrefcount(u1)-1) # NameError: name 'u1' is not defined12345678910111213
引用+1场景
  1. 对象被创建会 +1 
    u1=Uranus()

  2. 对象被引用会 +1 
    u2=u1

  3. 对象作为参数传入到一个函数中会 +2

    import sysclass Uranus:
        passu1 = Uranus()def func(obj):
        print(sys.getrefcount(obj)-1)
    func(u1)

    为什么会+2呢?python3的有点难理解,但是Python2的可以直接打印一下 
    print([(i,getattr(func,i)) for i in dir(func)]) 
    可以看到__globals__he funcglobals__都存在u1

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

对象作为一个元素,存储在容器中会 +1 
list1=[u1]

引用-1的场景
  1. 对象被销毁 
    del u1

  2. 对象被赋予新的值 
    u1=Uranus() u1=1

  3. 一个对象离开他的作用域

    如上面对象传入某个函数中,当函数执行完成后,引用会立即销毁

  4. 对象所在的容器被销毁 
    list1=[u1] del list1

特殊场景-循环引用问题

何为循环引用?怎么去计算? 
此时我们需要使用一个模块objpraph

Count objects tracked by the garbage collector with a given class name.

import objgraph # 需要单独下载class Person:
    passclass Animal:
    passprint(objgraph.count("Person")) # 0print(objgraph.count("Animal")) # 0P = Person()
A = Animal()
print(objgraph.count("Person")) # 1print(objgraph.count("Animal")) # 1P.pet = A
A.master = Pdel Pdel A# 正常情况下,如果删除了P和A,应该为0,但由于循环引用,结果为1print(objgraph.count("Person")) # 1print(objgraph.count("Animal")) # 11234567891011121314151617181920

那这样不是GG思密达了?那怎么阔能!!!真这样的话Python还有谁用呢?

垃圾回收机制

从经历过引用计数器机制仍未被释放掉的对象中,找到循环引用并删除相关对象

何时启动垃圾回收

不是说你创建了一个变量,就会马上开始垃圾回收的! 
需要你代码中,新增对象-消亡对象阈值达到某一个零界点是才会启动垃圾回收 
如何查看这个阈值呢?需要引入GC模块

import gc
print(gc.get_threshold())

output:
(700, 10, 10)12345

代码的结果是一个元组,后面两位之后说,700代表python设置的阈值

怎么找到循环引用
  1. 搜集所有容器对象,通过双向列表进行引用

    容器对象:list couple dict … 
    非容器对象:a=10 …

  2. 针对每一个容器对象,通过一个变量gc_refs来记录当前对应的引用计数

  3. 对于每一个容器对象,找到它引用的容器对象,并将这个容器对象的引用计数-1

  4. 如果经历以上三次,如果一个容器对象的引用次数为0,就代表可以被回收了

通过上面的循环引用查找,也许有的人认为比较简单,但是如果一个大的项目,存在着成千上万的容器对象,这么每次去检测岂不是要累死? 
python考虑到此处,所以创建了一套回收机制,叫做分代回收

分代回收

何为分代回收,当第一次检测完成后,部分的容器对象没有为0,则将其从0代移动至1代对象中,当检测10次后,在第11次时,会再次扫描0代1代的对象,当101次,即1代对象也被检测了10次,仍存在未被回收的容器对象时,会将器移动至2代中。多像爷爸孙…. 
至于为什么是10,就是刚才我们查看gc.get_threshold()得到的元组后两个字段。 
当然我们也可以进行手动设置: 
gc.set_threshold(100,5,5) 
但劝你没事儿还是别瞎折腾….

暂停暂停了…

今天有点晚了,先学到这里吧,明天接着搞起….


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。