Python 内存管理和垃圾回收

本文详细解释了Python中的垃圾回收机制,包括引用计数器原理、环状双向链表的应用、对象的PyObject结构,以及标记清除和分代回收策略来处理循环引用问题。同时介绍了Python缓存中的池和freelist机制。
摘要由CSDN通过智能技术生成

一旦提到 垃圾回收机制就会关联到:引用计数器为主,标记清楚和分代回收为辅+缓存机制

但是一旦问到如何实现?

那么可能就不太好能回答清楚

1.引用计数器

1.1 环状双向链表refchian

python中创建的任何对象 都会放在refchain中

在C源码中如何体现每个对象都有相同的值:PYOBject结构体

封装了4个值:上一个对象、下一个对象、引用个数、数据类型

由多个元素组成的对象:PyObject结构体(4个值)+ob_size

1.2类型封装结构体

1.3引用计数器

  回收:1、对象从refchain链表移除,2、将对象销毁、内存归还

引用技术器的bug:

循环引用的 问题:

循环引用和交叉感染

V1、V2应该是要被回收,但是引用计数器并非为0,所以就会出现循环引用的问题。

那么如何解决?

2、引入标记清除来解决

如何实现?

在python的底层再去维护一个链表,链表中专门存放哪些可能存在循环引用的对象(列表,字典,元组,集合)

比如:

第一个refchain不变,第二个链表存放可能会存在循环引用的对象,

在内部,某种情况下会扫描可能循环引用的列表中的每个元素,检查是否有循环引用,如果有,则让双方的计数器,各自减1,如果为0则垃圾回收。

问题:

什么时候扫描?

可能存在循环引用的链表扫描代价大,每次扫描耗时久

3、分代回收

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

0代:0代中对象个数达到700个扫描一次,最开始的对象创建都会添加到0代里面去,直到0代达到了700以后,就会对他进行扫描,如果是循环引用就自减1,如过是垃圾就自动回收,如果不是垃圾就让他升级为1代。这样第一次扫描完,是垃圾就回收,不是就升级,并标记扫描一次了。这样循环了10次之后,才会扫描一代。

1代:0代扫描10次,则1代扫描1次

2代:1代扫描10,则二代扫描一次i

4、小结

首先在python中有维护了一个refchain的双向链表,这个链表中存储程序创建的所有对象,每种类型的对象中有一个ob_refcnt引用计数器的值,引用个数+1,-1,最后当引用计数器变为0的时候就会进行垃圾回收,要么是对象销毁,就是从refchain中移除。

但是对于python中的那些可以有多个元素组成的对象可能会存在循环引用的问题,为了解决这个问题,那么就引入了标记清楚和分代回收,在其内部维护了4个链表,refchain和0代1代和2代。

在源码的内部,当达到各自的阈值时候就会扫描链表进行标记清除的动作(有循环则各自减1)

但是在python的源码内部又提出了优化机制。

5、Python缓存

5.1池

在内部池内,计数器不可能为0.

5.2 free list机制(float/list/tuple/dict)

当引用计数器为0时,按理说应该回收,内部不会去回收,而是将对象添加到free_list链表中当缓存,以后再去创建对象时候,不再重新开辟内存,而是直接free_list

C中源码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值