首页 > 编程语言 >python的垃圾回收

python的垃圾回收

时间:2024-04-06 13:58:18浏览次数:14  
标签:python list free 对象 垃圾 print 回收 引用

引用计数器为主,标记清除和分代回收为辅

1 引用计数器

在这里插入图片描述

在python程序运行时,会根据数据类型的不同找到其对应的结构体,根据结构体中的字段来进行创建相关的数据,然后将对象添加到refchain双像链表中,每个对象中的ob_refcnt就是引用计算器,值默认是为1,当有其他的变量引用对象时,引用计数器就会发生变化。

当一个对象的ob_refcnt为0时,会进行垃圾回收,将对象从refchain链表中移除,将对象销毁,内存回收

2 标记清除

标记清除存在的问题:循环引用
在这里插入图片描述
在这里插入图片描述
为了解决循环引用的问题,python引入了标记清除的技术:在python底层再维护一个链表,链表中专门存放可能存在循环引用的的对象(list/tuple/dict/set),在python内部的某种情况下下触发会去扫描标记情况中的每个元素,检查是否有循环引用如果有则让双方的引用计数-1,refcnt为0则垃圾回收。

3 分代回收

标记清除存在两个问题

  1. 什么时候去扫描标记清除的链表
  2. 扫描标记清除的链接扫描的代价大,每次扫描耗时比较久

将标记清除的链表分为三代

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

分代清除解决什么时候去扫描扫描耗时的问题,当0代的对象个数达到700时会扫描0代计数为0的垃圾回收,否则升级为1代,当0代扫描了10次时会扫描1代,计数器为0清除,否则升级为2代

4 python缓存机制

为了优化python对内存的使用底层使用了多种缓存机制

在这里插入图片描述

4.1 小整数池

a = 10
b = 10

print(a == b)   # True
print(a is b)   # True

python 中经常使用的一些数组定位为小整数池,小整数池的范围为**-5~256**,python对这些数值已经提前创建好了内存地址,即使多次重新定义也不会重新开辟新的空间,但小整数池外在重新定义时会再次开辟新的空间,锁小整数池中的内存地址时相同的

4.2 不可变类型缓存

a = 100000000000000000
b = 100000000000000000

print(a == b)   # True
print(a is b)   # True

a = "aaa"
b = "aaa"
print(a == b)   # True
print(a is b)   # True

a = 12.2
b = 12.2
print(a == b)   # True
print(a is b)   # True

a = (1, 2, 3)
b = (1, 2, 3)
print(a == b)   # True
print(a is b)   # True

pyhon解释器启动时会先从内存中开辟出来一小块内存,用于存储高频使用的数据(不可变类型,数字、字符串、元组),这样可以大大减小使用数据的对象时申请内存和销毁内存的开销。在同一块代码下,不可变类型的对象被多个变量引用,不会重复开辟内存空间,可变类型(字典、列表、集合)被多个变量创建时会重新开辟新的内存地址

而交互模式下,不会使用缓存机制

4.3 字符驻留

#交互模式
>>> s1='hello'
>>> s2='hello'
>>> print(s1 is s2)
True

字符串作为python最为常用的数据类型,python为了提高字符串的使用效率和使用性能,使用了intern(字符串驻留)来提高字符串的效率,即使同样的字符串对象仅仅会保存一份,放在一个和字符串储存池中,是共用的,有新的变量引用同样的字符串时候,不会开辟新的内存空间,而是引用这个共有的字符串。所以在交互模式下字符也是同一个对象

满足字符驻留的条件

  1. 在交互模式下,只包含字母数字下划线的字符串才会触发 intern 机制
  2. 在 IDE 环境或者脚本模式下,只要长度不超过20(长度限制),即使使用特殊字符也会触发 intern 机制
  3. 用的是 python 3.9,发现没有长度限制了,都会触发 intern 机制

4.4 free_list

当一个对象的引用计算器为0时,按道理说应该回收,但是内部不会直接直接将开辟的内存空间直接回收,而是将对象放在free_list链表中当缓存,以后再去创建对象时不再重新开辟内存而是直接使用free_list的对象。(float/list/tuple/dict)

v1 = 3.14
del v1

当运行这段代码会创建一个float对象,并将其加到refchain中。接下来执行删除操作,这时候v1的引用计数器变为零,这时候理应对v1执行垃圾回收,将其从refchain中进行摘除,并从内存中进行消除。但是实际上,Python会将这个对象存放到free_list中。当以后创建一个变量v9=999.99,这时候Python就不会重新开辟内存,而是直接从free_list获取这个对象,获取到对象之后对对象中的数据进行初始化,再放到refchain中,这也是一种优化机制。

free_list不会把每一个对象都放进来,free_list假设最多能放80个,当del了80个,这些对象都会存放在free_list中,当del第81个对象时,因为free_list已经满了,因此不会缓存到free_list中,这个时候才会对对象进行销毁。

5 源码分析

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.1 创建float对象

var = 3.14

在这里插入图片描述
创建一个float对象的时候

  1. 首先会去查询free_list中是否为空,为空会malloc一块新的内存空间,否则从free_list中获取一块内存。
  2. 之后对PyObject初始化如引用计数器初始化为1,添加到refchain链表中
  3. PyObject对象的ob_fval进行赋值
  4. 返回PyObject的指针

5.2 引用 float对象

val = 3.14
val1 = val

在这里插入图片描述
出现引用的时候,会将原来PyObject中的ob_refcnt+1

5.3 销毁float对象

var = 3.14
del var

在这里插入图片描述
销毁对象时,会将引用计数器-1,如果引用计数器为0则执行Dealloc进行垃圾回收,否则啥事情都不做

标签:python,list,free,对象,垃圾,print,回收,引用
From: https://blog.csdn.net/weixin_43413871/article/details/137356455

相关文章

  • python画带阴影折线图
    (1)#coding=gbkimportmatplotlib.pyplotaspltimportnumpyasnp#创建一些示例数据x=np.linspace(-3,3,60)y_mean=np.sin(x)y_std=np.sin(x)#画折线图b-:蓝色实线plt.plot(x,y_mean,'b-',label='Mean')#填充阴影表示标准差alpha:阴影......
  • 【Python基础】元组
    文章目录@[toc]什么是元组元组与列表的区别与联系可变性使用场景相似性索引示例索引越界切片语法示例步长为正步长为负遍历元组什么是遍历for循环遍历while循环遍历可变类型与不可变类型可变类型不可变类型元组中的不可变与可变示例个人主页:丷从心.系列专栏......
  • Python基础笔记-day01
    Python基础-day1!!!注意:本系列所写的文章全部是学习笔记,来自于观看视频的笔记记录,防止丢失。观看的视频笔记来自于:哔哩哔哩武沛齐老师的视频:2022Python的web开发(完整版)入门全套教程,零基础入门到项目实战1.文档工具typora2.环境搭建安装Python解释器学习Python语法Python......
  • 【Mathematical Model】基于Python实现随机森林回归算法&特征重要性评估&线性拟合
    ​    前段时间在做遥感的定量反演,所以研究了一下回归算法,由于之前发的几篇博文都是定义好基础方程进行拟合的,不太满足我的需求。所以研究了一下随机森林回归的算法,之前使用随机森林都是做分类,这次做了回归算法也算是补全了RF算法的空缺了。今天抽空给大家分享一下使用P......
  • 【个人笔记】如何用 Python 编写激活码解锁程序
    目录前言第一步:编写激活码解锁程序(激活码.py)第二步:修改需要解锁的程序(1.py) 总结前言在软件开发中,有时候我们需要设计一种机制来保护程序,例如通过激活码来控制程序的使用权限。本文将介绍如何使用Python编写一个简单的激活码解锁程序,以及如何修改另一个程序来检测是否......
  • 【Python&RS】基于GDAL遥感影像分幅裁剪(固定尺寸)
    ​    之前分享过一篇分幅裁剪的文章:【Python&RS】基于GDAL遥感影像分幅裁剪,只不过这篇文章当时编写的逻辑是自己输入需要裁剪多少行多少列,由于大家可能并没有直观地希望自己裁剪多少行列,所以非常局限。今天跟大家分享一下使用固定尺寸对遥感影像进行分幅裁剪,即每张裁剪......
  • 华为OD机试 - 猴子爬山(Java & JS & Python & C & C++)
    须知哈喽,本题库完全免费,收费是为了防止被爬,大家订阅专栏后可以私信联系退款。感谢支持文章目录须知题目描述输入描述输出描述用例解题思路:Java代码:JS代码:Python代码:C代码:C++代码:题目描述一天一只顽猴想去从山脚爬到山顶,途中经过一个有个N个台......
  • 华为OD机试 - 火星文计算(Java & JS & Python & C & C++)
    须知哈喽,本题库完全免费,收费是为了防止被爬,大家订阅专栏后可以私信联系退款。感谢支持文章目录须知题目描述输入描述输出描述用例解题思路:Java代码:JS代码:Python代码:C代码:C++代码:题目描述已知火星人使用的运算符为#、$,其与地球人的等价公式如下......
  • Python中的iif语句这样用(使用三元表达式替代if-else语句)
    #使用三元表达式替代if-else语句scope=n.name.startswith("'")and'工作表'or'工作簿'#ifn.name.startswith("'"):#scope='工作表'#else:#scope='......
  • 1.4Python环境安装
    1、安装包的下载进入Python官网:WelcometoPython.org以win系统64位为例,下载安装包:Python3.12.2下载完成准备安装:2、安装步骤2-1、如下图勾选:安装时使用管理员权限,添加python的环境变量        并选择自定义安装2-2、点击【Next】2-3、选择文件路径,使用......