python内存管理及垃圾回收

1. 引用计数器

1.1 环状双向连表 refchain

在python程序中创建的任何对象都会放在refchain链表中,并且可以通过这个对象访问到上一个和下一个对象。

name = '张三'
age = 18
hobby = ['美女','吃饭']
内部会建立一些数据 -打包 C语言叫做结构体-> 【上一个对象、下一个对象、类型、引用个数】
name = "张三"   # 创建一个对象开辟内存空间
new = name  # new指向指向"张三"这块内存,不会重新分配内存,引用计数+1内部会建立一些数据 【上一个对象、下一个对象、类型、引用个数、val=18】
age = 18   # int会添加具体值内部会建立一些数据 【上一个对象、下一个对象、类型、引用个数、items=元素、元素个数】
hobby = ['美女','吃饭']  # 列表会添加元素和元素个数

C语言源码

  • 每个对象都有相同的值:PyObject 结构体 (4个值)。
  • 有多个元素组成的对象:PyObject 结构体 (4个值) + ob_size 。
#define PyObject_HEAD       PyObject ob_base;
#define PyObject_VAR_HEAD      PyVarObject ob_base;// 宏定义,包含 上一个、下一个,用于构造双向链表。(放到refchain链表中时会用到)
#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;typedef struct {PyObject ob_base;   // PyObject对象Py_ssize_t ob_size; /* Number of items in variable part,即:元素个数 */
} PyVarObject;

源码解析,包含:

  • 2个结构体

    • PyObject,此结构体中包含3个元素。

      • _PyObject_HEAD_EXTRA,用于构造双向链表。
      • ob_refcnt,引用计数器。
      • *ob_type,数据类型。
    • PyVarObject,次结构体中包含4个元素(ob_base中包含3个元素)
      • ob_base,PyObject结构体对象,即:包含PyObject结构体中的三个元素。
      • ob_size,内部元素个数。
  • 3个宏定义
    • PyObject_HEAD,代指PyObject结构体。
    • PyVarObject_HEAD,代指PyVarObject对象。
    • _PyObject_HEAD_EXTRA,代指前后指针,用于构造双向队列。

1.2 不同类型封装的结构体

# float类型
data = 3.14内部会创建:_ob_next = refchain 中的上一个对象_ob_prev = refchain 中的下一个对象 ob_refcnt = 1 ob_type = floatob_fval = 3.14

C源码:

typedef struct {PyObject_HEADdouble ob_fval;
} PyFloatObject;

1.3 引用计数器

v1 = 3.14
v2 = 999
v3 = [1,2,3]

当python程序运行时,会根据数据类型的不同找到其对应的结构体,根据结构体中的字段进行创建相关的数据,然后将对象添加到refchain双向链表中。

在C源码中有两个关键的结构体:PyObject、PyVarObject。

每个对象中有ob_refcnt 就是引用计数器,默认值为1,当有其他变量引用对象时,引用计数器就会发生变化。

  • 引用

    a = 999
    b = a    # 999 这个对象的引用计数器+1,为2
    
  • 删除引用

    a = 999
    b = a
    del b  # b变量删除,b对应的对象的引用计数器 -1
    del a  # a变量删除,a对应的对象的引用计数器 -1 (a、b对应同一个对象)"""
    当一个对象的引用计数器为0时,意味着没有人可以使用这个对象了,这个对象就是垃圾,需要被回收
    回收:1.对象从refchain链表中移除2.将对象销毁,内存归还系统"""
    

    1.5 循环引用

2. 标记清除

目的:为了解决引用计数器循环引用的不足。

实现:在python的底层 再维护一个链表,链表中专门放那些可能存在循环引用的对象 (list/tuple/dict/set)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-V9eqdYfm-1605967623655)(E:\07-notes\picture\57_解决循环引用图.png)]

在python内部 某种情况下 触发,会去扫描 可能存在循环引用的链表中的每一个元素,检查是否有循环引用,如果有则双方的引用计数器 -1,如果是 0 则垃圾回收。

问题:

  • 什么时候扫描?
  • 可能存在循环引用的链表扫描代价较大,每次扫描耗时久。

3. 分代回收

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K55asNPj-1605967623657)(E:\07-notes\picture\58_分待回收图
.png)]

将可能存在循环引用的对象维护成 3个链表:

  • 0代:0代中对象个数达到700个扫描一次;
  • 1代:0代扫描 10 次,则 1代扫描一次;
  • 2代:1代扫描10次,则 2 代扫描一次。

4. 小结

在python中维护了一个refchain的双向环状链表,这个链表中存储程序中创建的所有对象,每种类型的对象都有一个 ob_refcnt 的引用计数器的值,对象被引用,则计数器的值 +1,引用被删除则计数器的值 -1,最后引用计数的值为 0 时,会进行垃圾回收(对象销毁、从refchain中移除),

但是,在python中对于那些可以有多个元素组成的对象可能会存在循环引用问题,为了解决这个问题python引入了 标记清除 ,在其内部再维护了一个链表,专门放那些可能存在循环引用的对象 (list/tuple/dict/set), 某种情况下 触发,会去扫描 可能存在循环引用的链表中的每一个元素,检查是否有循环引用,如果有则双方的引用计数器 -1,如果是 0 则垃圾回收,

然而,又有一个新的问题产生,就是什么时候扫描?可能存在循环引用的链表扫描代价较大,每次扫描耗时久,所以又引入了 分代回收 ,将可能存在循环引用对象维护成 3 个链表,分别是 0代,1代,2代,所有可能存在循环引用的对象都存储在 0代链表,当对象个数达到700个的时候扫描一次,是垃圾则回收,不是则移代 1代,依次类推,0代扫描10次,1代扫描一次,1代扫描10次,2代扫描1次。

e=5>分代回收 ,将可能存在循环引用对象维护成 3 个链表,分别是 0代,1代,2代,所有可能存在循环引用的对象都存储在 0代链表,当对象个数达到700个的时候扫描一次,是垃圾则回收,不是则移代 1代,依次类推,0代扫描10次,1代扫描一次,1代扫描10次,2代扫描1次。

Python 的垃圾回收回收机制(源码)相关推荐

  1. android进阶篇02、RecyclerView回收复用机制源码解析,h5移动端开发进行定位

    public void removeAndRecycleViewAt(int index, @NonNull Recycler recycler) { final View view = getChi ...

  2. Hotspot 垃圾回收之GenCollectedHeap 源码解析

    目录 1.定义 2.构造方法 / initialize / post_initialize 3.do_collection 4.do_full_collection 5.collect 6.VM_Ge ...

  3. 最新旧物回收类网站源码V2.4版+Thinkphp内核

    正文: 旧物回收类网站源码系统是一款开源的thinkphp5.0 的 Blog系统,其衍生于优秀的内容管理系统易优cms. 旧物回收类网站源码系统秉承了易优cms的先进设计理念,并且专注于旧物回收. ...

  4. python二手交易平台代码_PYTHON爬虫实战_垃圾佬闲鱼爬虫转转爬虫数据整合自用二手急速响应捡垃圾平台_3(附源码持续更新)...

    说明 文章首发于HURUWO的博客小站,本平台做同步备份发布. 如有浏览或访问异常图片加载失败或者相关疑问可前往原博客下评论浏览. 原文链接 PYTHON爬虫实战_垃圾佬闲鱼爬虫转转爬虫数据整合自用二 ...

  5. 计算机毕业设计Java二手手机回收平台系统(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Java二手手机回收平台系统(源码+系统+mysql数据库+lw文档) 计算机毕业设计Java二手手机回收平台系统(源码+系统+mysql数据库+lw文档) 本源码技术栈: 项目架构:B ...

  6. Python concurrent.future 使用教程及源码初剖

    前言 原文发在这里的 Python concurrent.future 使用教程及源码初剖 垃圾话 很久没写博客了,想了想不能再划水,于是给自己定了一个目标,写点 concurrent.future ...

  7. React事件机制 - 源码概览(下)

    上篇文档 React事件机制 - 源码概览(上)说到了事件执行阶段的构造合成事件部分,本文接着继续往下分析 批处理合成事件 入口是 runEventsInBatch // runEventsInBat ...

  8. ART虚拟机 | Cleaner机制源码分析

    目录 思考问题 1.Android为什么要将Finalize机制替换成Cleaner机制? 2.Cleaner机制回收Native堆内存的原理是什么? 3.Cleaner机制源码是如何实现的? 一.版 ...

  9. 仿猎豹垃圾清理 实现原理+源码

    仿猎豹垃圾清理(实现原理+源码) 转载请注明出处: 仿猎豹垃圾清理(实现原理+源码) 前几天无意打开猎豹内存大师, 发现它的垃圾清理很强大, 效果也不错, 闲着就研究了下. 不过.. 结果貌似和我想象 ...

  10. 仿猎豹垃圾清理(实现原理+源码)

    仿猎豹垃圾清理(实现原理+源码) 转载请注明出处: 仿猎豹垃圾清理(实现原理+源码) 前几天无意打开猎豹内存大师, 发现它的垃圾清理很强大, 效果也不错, 闲着就研究了下. 不过.. 结果貌似和我想象 ...

最新文章

  1. 生态伙伴 | 番茄君入驻飞书,帮你一招搞定时间管理,告别拖延症!
  2. 计算机组成原理汇编程序实验,计算机组成原理汇编实验(资料).pdf
  3. Python:23种Pandas核心操作
  4. 将某内存单元数据做乘法 + 内存间数据的复制
  5. 338. Counting Bits(动态规划)
  6. java中比较两个日期的大小
  7. Quick Cocos2dx 场景转换问题
  8. 硬件知识:电脑硬盘的数据保护与恢复,新手必备的知识!
  9. post获取重定向的链接 python_【转载】python面试基础知识(四) 网络部分
  10. vue项目中axios的封装
  11. matlab 自适应波束,(完整word版)自适应波束形成与Matlab程序代码注解
  12. 拓端tecdat|R语言逻辑回归(Logistic Regression)、回归决策树、随机森林信用卡违约分析信贷数据集
  13. 阶段3 2.Spring_08.面向切面编程 AOP_6 四种常用通知类型
  14. 如何管理软件测试环境
  15. 【MapGIS精品教程】002:GDB本地数据库的使用
  16. Android之布局详解
  17. tp前后端不分离源码_Thinkphp5.0+Vue2.0前后台分离框架通使用后端源码
  18. 手机远程共享计算机文件,电脑如何共享文件到手机
  19. js将阿拉伯数字转化成大写
  20. HTML 有序列表 字母,HTML之有序列表教程

热门文章

  1. 3点 刚体运动 opencv_模态法动力学分析中的刚体模态
  2. 深度学习平台的未来:谁会赢得下半场?
  3. 【JavaWeb】JDBC优化 之 数据库连接池、Spring JDBC
  4. ubuntu-18.04 修改用户名密码
  5. path环境变量丢失恢复
  6. 从Airbnb的发展历程和网易云的大起大落看IT行业创新(第5周课后作业)
  7. java编程思想第四版第十四章 类型信息习题
  8. 『实践』Matlab实现Flyod求最短距离及存储最优路径
  9. redis 简单应用
  10. 关于直播,所有的技术细节都在这里了(2)《转载》