有很多不同的方法来实现垃圾回收,例如跟踪,引用计数,转义分析,时间戳和心跳信号等。不同的语言依赖于不同的垃圾回收实现,例如,有些将其与编译器和运行时系统集成在一起。而其他语言则可能需要事后设置,甚至可能需要重新编译。Python中垃圾收集器使用基于引用计数的方法。它在程序执行期间运行,并在对象的引用计数达到0时开始工作。

1、引用管理

首先,内存管理是基于引用的管理。我们知道Python中,引用与对象是分离的,一个对象可以有多个引用,而每个对象都存有指向自己的引用计数。可以使用标准库sys查看某个对象的引用计数:

from sys import getrefcount

a = [1,2,3]
print(getrefcount(a)) # 打印2 b = a
print(getrefcount(a)) # 打印3

由于调用getrefcount()时又创建了一次引用,所以打印的引用计数会比实际多一个。

2、对象引用对象

Python中对象会引用别的对象,而容器对象的引用会构成很复杂的拓扑结构:

l = [1,2,3]
d = {"k": l} y = [l, d]
z = [y,(l,y)]

使用 objgraph 包可以绘制引用关系:

...
import objgraph
objgraph.show_refs([z], filename='sample-graph.png')

绘制的 z 对象的引用图如下:

3、引用环

两个对象相互引用,即构成了所谓的引用环

a = []
b = [a]
a.append(b) objgraph.show_refs([a,b], filename='a-b.png')

即使是单个对象,只需自己引用自己,也会构成引用环:

a = []
a.append(a) objgraph.show_refs([a], filename='a-b.png')

del关键字除了可以删除容器中的元素,还可以删除某个引用。

4、垃圾回收

CPython中的内存管理和垃圾回收有两个策略:

  • 引用计数

  • 分代回收

4.1 引用计数

CPython中主要的垃圾收集机制是通过引用计数,且引用计数无法被禁用,而后面谈到的分代回收策略则可以禁止。

原理上,Python的某个对象的引用计数变为0时,就要成为被回收的垃圾了。例如:

a = [1,2,3]
del a

当垃圾回收启动时,Python扫描到这个引用计数为0的对象,会将其所占据的内存清空。而垃圾回收是个费时费力的事,垃圾回收期间Python不能进行其他任务。频繁的垃圾回收会大大降低Python的效率,所以Python只会在特定条件下启动垃圾回收。Python运行时,会记录其中分配对象和取消分配对象的次数,当两者差值高于某个阈值,垃圾回收才会启动。

有人说引用计数是一个穷人的垃圾收集器。它确实有一些缺点,包括无法检测到循环引用。但是,引用计数的优点是,你可以在没有引用的情况下立即删除该对象。

4.2 分代回收

除了上面这种实时的自动的基于引用计数的垃圾回收实现方法,Python还同时采用分代回收策略,这一次略的基本假设是,存活时间越久的对象,越不可能在以后成为垃圾。Python将所有对象分为三代,所有新建对象都是0代,如果经过一次扫描没被回收即成为了1代,以此类推。

Python的基于引用计数的方法是自动的,并且是实时发生的,而分代垃圾回收模块的操作是周期性的,可以手动调用,常用API:

  • get_shreshold()方法可以查看触发垃圾收集的阈值:

  • gc.get_count()方法可以查看内存中当前存在的各代对象数量

  • gc.set_threshold()方法可以更改触发垃圾收集的阈值

>>> import gc
>>> print(gc.get_threshold()) # (700, 10, 10)
>>> gc.set_threshold(700.10,5) # 2代垃圾回收会更频繁
>>> gc.collect() # 手动触发垃圾回收

对于每一代,垃圾收集器模块都有一个阈值对象。如果对象数超过该阈值,则垃圾收集器将触发收集过程,在该过程中幸存下来的对象会被归为下一代。默认情况下,Python对于最年轻的一代的阈值为700,对于两个较老的一代中的每个阈值为10。

引用环的回收

分代回收策略可以可以检测和解决引用环问题,在Python 1.5中引入了循环检测算法,它跟踪容器对象,即可以容纳其他对象(例如列表,字典,类等)的对象,因为只有它们才能创建此这种引用环。

循环检测算法的基本原理是:Python会复制每个对象的引用计数,记为gc_ref。假设每个对象为i,该对象的计数为gc_ref_i。Python会遍历所有的对象i,对于每个对象i所引用的对象j,将jgc_ref_j减1:

遍历后,gc_ref不为0的对象及这些对象引用的对象,以及更下游的对象会被保留,而引用环中的对象会被回收。

参考

Python:垃圾回收的更多相关文章

  1. Python垃圾回收机制--完美讲解!

    转自: http://www.jianshu.com/p/1e375fb40506 先来个概述,第二部分的画述才是厉害的. Garbage collection(GC) 现在的高级语言如java,c# ...

  2. python垃圾回收机制与小整数池

    python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...

  3. python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除

    js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...

  4. python 垃圾回收

    # 垃圾回收 # 小整数对象池 # a = 100# python对小整数的定义是[-5,257],这些证书对象是提前创建好的,不会被垃圾回收,再一个python的程序中,所有位于这个范围内的正式使用 ...

  5. python垃圾回收

    python垃圾回收 python垃圾回收主要使用引用计数来跟踪和回收垃圾.在引用计数的基础上,通过“标记—清除”解决容器对象可能产生的循环引用问题,通过“分代回收”以空间换时间的方法提高垃圾回收效率 ...

  6. 《垃圾回收的算法与实现》——Python垃圾回收

    Python垃圾回收 python采用引用计数法进行垃圾回收 Python内存分配 python在分配内存空间时,在malloc之上堆放了3个独立的分层. python内存分配时主要由arena.po ...

  7. python垃圾回收机制(Garbage collection)

    由于面试中遇到了垃圾回收的问题,转载学习和总结这个问题. 在C/C++中采用用户自己管理维护内存的方式.自己管理内存极其自由,可以任意申请内存,但也为大量内存泄露.悬空指针等bug埋下隐患. 因此在现 ...

  8. python 垃圾回收详解

    原文:https://zhuanlan.zhihu.com/p/31150408 总纲 策略和垃圾回收系统工作内容 引用计数详解 标记-清除+分代收集 循环引用 编程应用-常见方法 ex 过程详解 使 ...

  9. python垃圾回收算法

    标准python垃圾回收器由两部分组成,即引用计数回收器和分代垃圾回收器(即python包中的gc module).其中,引用计数模块不能被禁用,而GC模块可以被禁用. 引用计数算法 python中每 ...

  10. python 垃圾回收笔记

    目录 引用计数 python内部的引用计数机制 循环引用 调试内存泄漏 总结 python 程序在运行的时候,需要在内存中开辟出一块空间,用于存放运行时产生的临时变量:计算完成后,再将结果输出到永久性 ...

随机推荐

  1. np.random.randint()的返回值

    返回的是数组而非int 比如返回x,y 为[1][2] 而非1,2 容易在只有一维一列时没有意识到 其他函数的返回值也要注意

  2. QXDM和QCAT软件使用指南

    一.传送门 链接:https://pan.baidu.com/s/1i55YXnf 密码:v6nw 二.QXDM,QPST和QCAT的简单说明 QXDM,QPST和QCAT是Qualcomm高通公司针 ...

  3. 痞子衡嵌入式:我的博文总量终于追平了jicheng0622

    自打2016年10月选定清爽又复古的博客园平台作为痞子衡的个人博客主战场之后,痞子衡就一直坚持在博客园首发原创技术文章,然后再同步到其他平台(CSDN,知乎,微信公众号...),在坚持更文近四年半(2 ...

  4. Inkscape 太慢

    问题: 在画板上图像较多时, 会在粘贴 / 删除 时会陷入长时间的等待 解决: 最佳: Ubuntu上面的比windows上的快上几十倍, 测试比较, 感觉并不是Ubuntu上多用了GPU, 总之, ...

  5. TypeScript Errors All In One

    TypeScript Errors All In One 1. Property 'name' has no initializer and is not definitely assigned in ...

  6. Android 开启 WebView 页面 Chrome debug

    Android 开启 WebView 页面 Chrome debug WebView debug // 开启 WebView 页面 debug testWebView.setWebContentsDe ...

  7. Android Kotlin 数据驱动模板

    Android开发人员文档: 数据绑定入门 数据绑定库 生成的绑定类 布局和绑定表达式 1. 搭建环境build.gradle:app apply plugin: "kotlin-kapt& ...

  8. NLog整合Exceptionless

    前言 在实际的.Net Core相关项目开发中,很多人都会把NLog作为日志框架的首选,主要是源于它的强大和它的扩展性.同时很多时候我们需要集中式的采集日志,这时候仅仅使用NLog是不够的,NLog主 ...

  9. Git 学习相关笔记

    Git Bash 相关命令学 基础概念 参考: https://www.cnblogs.com/gaoht/p/9087070.html https://www.runoob.com/git/git- ...

  10. django学习-23.admin管理后台的数据表数据的自定义展示

    目录结构 1.前言 2.自定义设置一张指定的数据表的列表展示内容 2.1.第一步:如果我们想让数据表[hello_person]里面的表字段值全部展示出来,需在应用[hello]里的[admin.py ...