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

引用计数算法

python中每个变量都是对象,每个对象核心都包含一个结构体PyObject:

 typedef struct_object {
int ob_refcnt;
struct_typeobject *ob_type;
} PyObject;

其中ob_refcnt变量记录了这个对象被引用的数量,当这个对象的引用被赋值给另一个变量或者这个引用被删除(如del a)。那么ob_refcnt就会随之加1或者减1。引用计数增加的场景有:

  • 赋值操作
  • 参数传递
  • 添加object到list末尾

如果某个对象的引用计数为0,那么python会立马调用函数释放内存空间,此时可能导致这个对象引用的其他对象引用计数也为0,因此一个对象消亡可能引起一连串对象内存空间被释放。

一般说来,全局变量(定义在函数,类和代码块之外的变量)随python进程退出而释放,因此引用计数永远不会减为0。局部变量(定义在函数,类和代码块之内的变量)反之。

引用计数算法原理简单明了,但是存在循环引用,线程锁和内存性能开销等问题。

分代垃圾回收算法

引用计数算法最大问题就是循环引用,这种情况下循环引用的每个对象的引用计数最终都不会归零,如下图所示:



因此,python在gc module实现了循环检测算法来解决这个问题。循环引用只可能发生在容器对象之间,因此,GC循环检测也只对容器对象使用。对于只包含常量的容器(如包含常量的tuple),GC也会把这部分排除掉。

GC将容器对象分为3代,定期清理每代的垃圾对象。新分配的对象总是在第0代,如果经历过一次垃圾回收依然存活则移入下一代。新生代的回收频率比老年代高,大部分新对象很快就会释放,因此生命周期都只是停留在第0代。这种分代回收方式可以提高GC性能,减少停顿时间。

GC进行时需要停止程序的执行以免引用关系改变。

为了确定何时可以执行垃圾回收,GC每一代维护都会count和threshold两个变量,其中count=上一次垃圾回收后分配的新对象-上一次垃圾回收后已经消亡对象(因为引用计数为0而被释放),每次对象创建时候都会比较count和threshold大小,如果count>threshold,python就会启动垃圾回收进程。

以下详细说明CPython循环检测的原理,CPython维护两个双向链表:一个是需要检测的对象关系链表(objects list),一个是存放无法访达的对象链表(Unreachable list)。

  1. 如下图所示,假设现在清理的是第0代的垃圾对象。左边的需要扫描的对象列表中link4是一个循环引用。varA是link1的外部引用,可能是其他代的对象。每个对象除了有一个引用计数变量ref count外,还维护一个gc_ref变量,初始时ref count=gc_ref.

  2. GC遍历objects list每个对象,将这个对象所引用的其他对象的gc_ref减1。
  3. GC将步骤2中gc_ref=0的对象挪到Unreachable list中,下图表示将已经处理的link3和link4移到Unreachable list,但是还没有处理link1和link2.
  4. 当GC扫描link1时候,发现gc_ref=1,是可以访达的,那么GC就会循环遍历link1引用的对象,将其标记为可以访达。因为link3经过此轮后标记为可以访达,那么就会将其从Unreachable list移到之前的list中。
  5. GC扫描完所有的对象后,就会启动垃圾回收进程,将Unreachable list中的对象清理掉。

为了性能考虑,我们应该尽量避免循环引用,可以使用weakrefmodule,weakref.ref不会增加对象的引用计数并且对象被回收后返回None。此外,可以使用gc.disable()手动关闭GC垃圾回收,这在某些特殊情况下有帮助。

参考资料

[1] Garbage collection in Python: things you need to know

[2] Python垃圾回收机制

[3] The Garbage Collector

[4] Python垃圾回收(GC)三层心法,你了解到第几层

python垃圾回收算法的更多相关文章

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

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

  2. Python垃圾回收机制

    引用计数Python默认的垃圾收集机制是“引用计数”,每个对象维护了一个ob_ref字段.它的优点是机制简单,当新的引用指向该对象时,引用计数 引用计数 Python默认的垃圾收集机制是“引用计数”, ...

  3. 深入理解java虚拟机【垃圾回收算法】

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

  4. (转)《深入理解java虚拟机》学习笔记3——垃圾回收算法

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

  5. C/C++中几种经典的垃圾回收算法

    1.引用计数算法 引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1:当删除一个指向自己的指针时,计数值减1,如果计数值减为0,说明 ...

  6. 深入理解java垃圾回收算法

    Java虚拟机的内存区域中,程序计数器.虚拟机栈和本地方法栈三个区域是线程私有的,随线程生而生,随线程灭而灭:栈中的栈帧随着方法的进入和退出而进行入栈和出栈操作,每个栈帧中分配多少内存基本上是在类结构 ...

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

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

  8. C++ 几种经典的垃圾回收算法

    之前遇到了一篇好文(https://blog.csdn.net/wallwind/article/details/6889917)准备学习一下的,课程繁忙就忘记了,今日得闲,特来补一下. 自己写一遍加 ...

  9. JVM垃圾回收算法及回收器详解

    引言 本文主要讲述JVM中几种常见的垃圾回收算法和相关的垃圾回收器,以及常见的和GC相关的性能调优参数. GC Roots 我们先来了解一下在Java中是如何判断一个对象的生死的,有些语言比如Pyth ...

随机推荐

  1. Java实现斐波那契数列Fibonacci

    import java.util.Scanner; public class Fibonacci { public static void main(String[] args) { // TODO ...

  2. thinkphp 中模型究竟是什么用?

    thinkphp 中模型究竟是什么用? 问题 似乎所有的操作都能在控制器中就能完成,模型除了几种验证之外,究竟是干什么用的,这个问题一直没理解透 解答 解答一 要明白这个问题,必须了解 MVC 历史. ...

  3. django session深入

    转至原文  https://www.cnblogs.com/zhaof/p/6281468.html 基于cookie做用户验证时:敏感信息不适合放在cookie中 session依赖cookie s ...

  4. 6.C语言文件操作之英语电子字典的实现,dos版

    多的不说,直接上代码: 里面涉及的字典文件在这:这是传送门,下载下来以后把该文件放在工程目录下即可 #define _CRT_SECURE_NO_WARNINGS #include <stdio ...

  5. BMP图片格式模型

    BMP BMP(全称Bitmap)是Window操作系统中的标准图像文件格式 可以分成两类:设备相关位图(DDB)和设备无关位图(DIB),使用非常广. 它采用位映射存储格式,除了图像深度可选以外,不 ...

  6. springMVC中跳转问题

    在使用SpringMVC时遇到了这个跳转的问题很头疼.现在总结出来,对以后的开发有所帮助. . 1.可以采用ModelAndView: @RequestMapping("test1" ...

  7. PostgreSQL Replication之第三章 理解即时恢复(2)

    3.2 归档事务日志 看过图片之后,我们可以看看如何使这些东西进入工作状态.当谈到及时归档时,您需要做的第一件事是归档XLOG.PostgreSQL通过postgresql.conf提供了所有与归档相 ...

  8. (VC)搭建OpenGL编程环境

    1.下载glut工具包 opengl需要用到的库.下载glut: http://pan.baidu.com/s/1i4c8sHf 2.安装glut a)解压上面下载到的glut工具包后会得到5个文件, ...

  9. 洛谷2850 【Usaco2006 Dec】虫洞Wormholes SPFA

    问题描述 John在他的农场中闲逛时发现了许多虫洞.虫洞可以看作一条十分奇特的有向边,并可以使你返回到过去的一个时刻(相对你进入虫洞之前).John的每个农场有M条小路(无向边)连接着N (从1..N ...

  10. 数据库Flashback学习

    最近更新时间:2018/12/18 适用场景 数据库升级.快速构建测试环境.DG中重建主库 前置条件 1. ARCHIVELOG 模式 数据库为 mount 状态下开启,最好指定archive log ...