CPython 垃圾收集器检测循环引用详解

 更新时间:2022年10月07日 12:17:33   作者:宇宙之一粟  
这篇文章主要为大家介绍了CPython 垃圾收集器检测循环引用详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

CPython 中的垃圾收集器

CPython 的垃圾收集器(简称GC)是 Python 内置的为了解决循环引用问题的方法。默认情况下,它总是在后台运行,并且每隔一段时间就会发挥它的魔力,所以你不必担心循环引用物会堵塞你的内存。

垃圾收集器被设计为从 CPython 的工作内存中找到并删除循环引用对象。它通过以下方式完成这一工作。

  • 检测循环引用的对象
  • 调用最终的 __del__ 方法
  • 它从每个对象中删除指针(以此来解决循环问题),只有当循环在步骤 2 之后仍然是孤立的

在这个过程完成后,以前在循环中的每个对象现在的引用计数都是 0 ,因此此对象将从内存中删除。

虽然它是自动工作的,但实际上我们可以把它作为一个模块从标准库中导入。举例如下:

import gc

检测循环引用

CPython 的垃圾收集器会跟踪内存中存在的各种对象--但不是所有的对象。我们可以实例化一些对象,看看垃圾收集器是否会收集它们。

>>> gc.is_tracked("a string")
False
>>> gc.is_tracked(["a", "list"])
True

如果一个对象可以包含指针,这就使它有能力形成循环引用结构的一部分--而这正是垃圾检测器存在的目的,即检测和拆除。在 Python 中这样的对象通常被称为 "容器对象"。

所以,垃圾收集器需要知道任何有可能作为循环引用的一部分而存在的对象。字符串不能,所以 "一个字符串 "不会被垃圾收集器追踪。列表(正如我们已经看到的)能够包含指针,因此 ['a', 'list'] 被跟踪。

用户定义的类的任何实例也将被垃圾收集器跟踪,因为我们总是可以在它们身上设置任意的属性(指针)。

>>> Wade = MyNameClass("Wade")
>>> gc.is_tracked(Wade)
True

所以,垃圾收集器知道所有有可能形成循环引用的对象。它怎么知道是否已经形成循环引用呢?

它也知道每个对象中的所有指针,以及它们所指向的位置。我们可以看到这个动作。

>>> my_list = ["a", "list"]
>>> gc.get_referents(my_list)
['list', 'a']

get_referents 方法(也称为遍历方法)接收一个对象,并返回它所包含的对象指针的列表(它的引用)。因此,上面的列表包含指向其每个元素的指针,这些元素都是字符串。

让我们在一个对象的循环中看看 get_referents 方法(虽然还不是一个循环引用,因为这些对象仍然可以从命名空间中被访问)。

>>> jane = MyNamedClass("Jane")
>>> bob = MyNamedClass("Bob")
>>> jane.friend = bob
>>> bob.friend = jane
>>> gc.get_referents(bob)
[{'name': 'bob', 'friend': <__main__.MyNamedClass object at 0x7ff29a095d60>}, <class '__main__

在这个循环中,我们可以看到由 bob 指向的对象包含指向以下内容的指针:它的属性字典,包含 bob 的名字 (bob) 和它的朋友 (同样由 jane 指向的 MyNamedClass 实例) 。bob 对象也有一个指向类对象本身的指针,因为 bob.class 将返回那个类对象。

当垃圾收集器运行时,它检查它所知道的每个对象(也就是当你调用 gc.is_tracked 时返回True的任何对象)是否可以从命名空间到达。它通过跟踪来自命名空间的所有指针,以及这些指针所指向的对象中的指针,以此类推,直到它建立起所有可从代码中访问的东西的整个视图。

如果在做完这些之后,GC 发现存在一些不能从命名空间到达的对象,那么它可以把这些对象清除掉。

记住,任何仍在内存中的对象必须有一个非零的引用计数,否则它们会因为引用计数而被删除。对于那些无法到达但仍有非零引用计数的对象,它们必须是循环引用的一部分,这就是为什么我们如此关心这些发生的可能性。

让我们回到引用循环,jane 和 bob,通过从命名空间中移除指针,把这个循环变成一个循环的隔离。

>>> del jane
>>> del bob

现在,我们已经了解了垃圾收集器所要解决的确切情况。我们可以通过调用 gc.collect() 来触发手动垃圾收集。

>>> gc.collect()
Deleting Bob!
Deleting Jane!
4

默认情况下,垃圾收集器会每隔一段时间自动执行这个动作(因为越来越多的对象在CPython运行时被创建和销毁)。

在上面的代码片段中,我们看到的输出包含了来自 MyNamClass 的 __del__ 方法的打印语句,在最后有一个数字--在这个例子中,是 4。 这个数字是由垃圾收集器本身输出的,它告诉我们有多少对象被移除。

参考链接:

https://anvil.works/articles/pointers-in-my-python-3

以上就是CPython 垃圾收集器检测循环引用详解的详细内容,更多关于CPython 垃圾收集器的资料请关注脚本之家其它相关文章!

相关文章

  • python爬虫增加访问量的方法

    python爬虫增加访问量的方法

    这篇文章主要介绍了python爬虫增加访问量的方法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友可以参考下
    2019-08-08
  • 基于Pytorch实现的声音分类实例代码

    基于Pytorch实现的声音分类实例代码

    声音分类是音频深度学习中应用最广泛的方法之一,下面这篇文章主要给大家介绍了如何基于Pytorch实现声音分类的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-06-06
  • python如何用pyecharts制作词云图

    python如何用pyecharts制作词云图

    大家好,本篇文章主要讲的是python如何用pyecharts制作词云图,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • Python format函数详谈

    Python format函数详谈

    这篇文章主要介绍了Python中用format函数格式化字符串的用法,格式化字符串是Python学习当中的基础知识,希望能够给你带来帮助
    2021-10-10
  • Python实现SICP赋值和局部状态

    Python实现SICP赋值和局部状态

    这篇文章主要介绍了Python实现SICP 赋值和局部状态的相关知识,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • python生成xml时规定dtd实例方法

    python生成xml时规定dtd实例方法

    在本篇文章里小编给大家整理的是关于python生成xml时规定dtd实例方法,需要的朋友们学习参考下。
    2020-09-09
  • 深入解析pandas数据聚合和重组

    深入解析pandas数据聚合和重组

    这篇文章主要介绍了pandas数据聚合和重组,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-04-04
  • Python中Jieba进行词频统计与关键词提取

    Python中Jieba进行词频统计与关键词提取

    本文主要介绍了Python中Jieba进行词频统计与关键词提取,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • 对Python中list的倒序索引和切片实例讲解

    对Python中list的倒序索引和切片实例讲解

    今天小编就为大家分享一篇对Python中list的倒序索引和切片实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-11-11
  • pandas筛选数值列和非数值列方式

    pandas筛选数值列和非数值列方式

    这篇文章主要介绍了pandas筛选数值列和非数值列方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02

最新评论