从 CPython 源码角度看 Python 垃圾回收机制
环状双向链表 refchain
在 Python 程序中创建的任何对象都会被放到 refchain 链表中,当创建一个 Python 对象时,内部实际上创建了一些基本的数据:
- 上一个对象
- 下一个对象
- 类型
- 引用个数
- 值
- 对于列表等类型,也会创建值用于存储列表的长度
在 C 源码中体现如下:
#define PyObject_HEAD PyObject ob_base;
#define PyObject_VAR_HEAD PyVarObject ob_base;
// 宏定义,包含:上一个、下一个、用于构造双向链表用
#define _PyObject_HEAD_EXTRA
struct _object *_ob_next;
struct _object *_ob_prev;
typedef struct _object {
_PyObject_HEAD_EXTRA
Py_ssize_t ob_refcnt; // 引用计数器
struct _typeobject *ob_type; // 数据类型
} PyObject;
// list、tuple、dict..
typedef struct {
PyObject ob_base; // PyObject 对象
Py_ssize_t ob_size; // 元素个数
} PyVarObject;
// float
typedef struct {
PyObject_HEAD
double ob_fval;
} PyFloatObject;
比如对于下面这段 Python 代码:
data = 3.14
其内部会创建:
_ob_next = refchain 中的下一个对象
_ob_prev = refchain 中的下一个对象
ob_refcnt = 1
ob_type = float
ob_fval = 3.14
引用计数器
在 Python 程序运行时,会根据数据类型的不同找到其对应的结构体,根据结构体中的字段来进行创建相关的数据,然后将对象添加到 refchain 双向链表中。
在 C 源码中有两个关键的结构体:PyObject、PyVarObject。
每个对象中都有 ob_refcnt,即引用计数器,默认值为 1,当有其他变量引用对象时,引用计数器就会发生变化。
当一个对象的引用计数器为 0 时,意味着没有人再使用这个对象了,这个对象就会被垃圾回收,流程如下:
- 把对象从 refchain 链表中移除
- 将对象销毁,内存归还
注:del 语句实际上就是在对引用计数器做 -1 操作。
循环引用

在 Python 底层,会维护一个新的链表,用于存放可能存在循环引用的对象(如 list/dict/set/tuple等)。当达到一定条件后,会去遍历每个元素,检查是否有循环引用,如果有,则让双方的引用计数 -1,如果是 0 则进行回收。
分代回收
循环引用引发了两个问题:
- 什么时候扫描?
- 扫描代价较大(对子孙元素都要进行扫描),单词扫描耗时久。
对此,Python 使用了分代回收的机制。将可能存在循环引用的对象维护成 3 个链表:
- 0 代,个数达到 700 个扫描一次
- 1 代,0 代扫描 10 次,1 代扫描 1 次
- 2 代,1 代扫描 10 次,2 代扫描 1 次
缓存
池(int)
为了避免重复的创建和销毁一些对象,维护池。
>>> a1 = 1
>>> a2 = 1
>>> id(a1)
140713557615440
>>> id(a2)
140713557615440
free_list(float/list/tuple/dict)
当一个对象的引用计数为 0 时,内部不会直接回收,而是将对象添加到 free_list 中当缓存,以后再去创建对象时,不再重新开辟内存,而是直接使用 free_list。
# 开辟新的内存
v1 = 3.14 # 将对象添加到 free_list 中
del v1 # 去 free_list 中获取对象,并将对象内存数据初始化
v2 = 999
参考
从 CPython 源码角度看 Python 垃圾回收机制的更多相关文章
- 简述Python垃圾回收机制和常量池的验证
目录 通过代码验证python解释器内部使用了常量池 Python的引入 变量的引入 为什么要有变量 定义变量 常量引入 常量池引入 Python解释器 Python变量存储机制 Python垃圾回收 ...
- 从JDK源码角度看Short
概况 Java的Short类主要的作用就是对基本类型short进行封装,提供了一些处理short类型的方法,比如short到String类型的转换方法或String类型到short类型的转换方法,当然 ...
- 从JDK源码角度看Byte
Java的Byte类主要的作用就是对基本类型byte进行封装,提供了一些处理byte类型的方法,比如byte到String类型的转换方法或String类型到byte类型的转换方法,当然也包含与其他类型 ...
- 从JDK源码角度看Object
Java的Object是所有其他类的父类,从继承的层次来看它就是最顶层根,所以它也是唯一一个没有父类的类.它包含了对象常用的一些方法,比如getClass.hashCode.equals.clone. ...
- 从JDK源码角度看Boolean
Java的Boolean类主要作用就是对基本类型boolean进行封装,提供了一些处理boolean类型的方法,比如String类型和boolean类型的转换. 主要实现源码如下: public fi ...
- python垃圾回收机制:引用计数 VS js垃圾回收机制:标记清除
js垃圾回收机制:标记清除 Js具有自动垃圾回收机制.垃圾收集器会按照固定的时间间隔周期性的执行. JS中最常见的垃圾回收方式是标记清除. 工作原理 当变量进入环境时,将这个变量标记为"进入 ...
- python垃圾回收机制与小整数池
python垃圾回收机制 当引用计数为0时,python会删除这个值. 引用计数 x = 10 y = x del x print(y) 10 引用计数+1,引用计数+1,引用计数-1,此时引用计数为 ...
- 浅析Python垃圾回收机制!
Python垃圾回收机制 目录 Python垃圾回收机制 1. 内存泄露 2. Python什么时候启动垃圾回收机制? 2.1 计数引用 2.2 循环引用 问题:引用计数是0是启动垃圾回收的充要条件吗 ...
- 从template到DOM(Vue.js源码角度看内部运行机制)
写在前面 这篇文章算是对最近写的一系列Vue.js源码的文章(https://github.com/answershuto/learnVue)的总结吧,在阅读源码的过程中也确实受益匪浅,希望自己的这些 ...
随机推荐
- Spring Cloud Gateway自定义过滤器实战(观测断路器状态变化)
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- [luogu4107]兔子和樱花
有两个贪心:1.自底向上dfs,能删就删,这样显然是正确的,因为它最多只会造成它父亲不能删除:2.对于一个节点,优先删除其代价($c[i]+son[i]$)最大的i删除,一定最优,证明略 1 #inc ...
- 史上最俗的MODBUS介绍
如今网购正深深地改变着人们的生活,以前买东西要逛商场,先找楼层导购,再逛到相应柜台,接着愉快购物,选好东西后经过一番讨价还价,最后付钱拿货走人,这些都是稀松平常的场景.可是,如果没有实际看见东西,只在 ...
- [Git专题] 环境搭建
环境搭建 在正式使用 Git 之前,首先应当安装 Git 并完成一些基础配置,本章内容就教大家在 Ubuntu 和 CentOS 上安装 Git 的方法. 安装 Git 客户端 如果你使用的是基于 D ...
- shell常用集锦
该文整理一些常用的shell用法,及语法,并非介绍如何使用 变量 变量可分为两类:环境变量ENV(全局)和局部变量. bash环境变量 变量名 含义 _= 上一条命令的最后一个参数 BASH_VERS ...
- 卸载.net 5.0后使用dotnet提示Found .NET Core SDK
之前安装了预览版本的vs2019后试了下,然后卸载了.但发现控制台执行dotnet相关命令提示Found .NET Core SDK, but did not find dotnet.dll at [ ...
- DirectX12 3D 游戏开发与实战第六章内容
利用Direct3D绘制几何体 学习目标 探索用于定义.存储和绘制几何体数据的Direct接口和方法 学习编写简单的顶点着色器和像素着色器 了解如何用渲染流水线状态对象来配置渲染流水线 理解怎样创建常 ...
- Mike post process with Matlab toolbox
表怕,这个博客只有题目是英文的-- Matlab toolbox 安装 去DHI官网下载最新的MikeSDK2014与Matlab toolbox,下载好后安装MikeSDK2014,注意电脑上不能有 ...
- printf 的 转义词 -转
\n 换行 \r 回车键 \b 退后一格 \f 换页 \t 水平制表符 \v 垂直制表符 \a 发出鸣响 \? 插入问号 \" 插入双引号 \' ...
- 用C语言的LED实验,有汇编哦!
C语言LED实验 1.汇编激活CPU 首先要明白对于没有系统开发板(也就是裸机)来说,是没办法直接对C进行识别.所以需要一段汇编语言,来配置CPU的资源,选择CPU运行模式,初始化指针位置. 代码如下 ...