python垃圾回收

1. 小整数对象池
整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池, 避免为整数频繁申请和销毁内存空间。

Python 对小整数的定义是 [-5, 256] ,这些整数对象是提前建立好的,不会被垃圾回收。在一个 Python 的程序中,所有位于这个范围内的整数使用的都是同一个对象。
如下所示:
在这里插入图片描述
2. 大整数对象池
每一个大整数,均创建一个新的对象。
如下所示:
在这里插入图片描述

3. intern机制(字符串驻留)
单个单词,不可修改,默认开启intern机制,共用对象,引用计数为0,则销毁。
在这里插入图片描述
字符串中包含空格等特殊字符,不可修改,没开启intern机制,不共用对象,引用计数为0,销毁。
在这里插入图片描述

4. Garbage collection(GC垃圾回收)
python里采用了垃圾收集机制,采用引用计数机制为主,分代收集机制为辅的策略,保证了内存尽量不出现垃圾。

引用计数
python中为了能够知道当前这个对象有多少变量指向它,因此会在每个对象中有一个小空间用于存放引用计数。
如:

a = xx() #此时实例对象中有个空间存储1,表示有1个变量指向这个实例对象
b = a     #对象的空间中由1变为2,表示有两个变量指向这个实例对象

引用计数机制的优点:

  • 简单
  • 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。

引用计数机制的缺点:

  • 维护引用计数消耗资源
  • 循环引用
list1 = []
list2 = []
list1.append(list2)
list2.append(list1)

其中list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。 对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将引入新的回收机制。(分代收集)

(1)导致引用计数+1的情况

  • 对象被创建,例如a=23
  • 对象被引用,例如b=a
  • 对象被作为参数,传入到一个函数中,例如func(a)
  • 对象作为一个元素,存储在容器中,例如list1=[a,a]

(2)导致引用计数-1的情况

  • 对象的别名被显式销毁,例如del a
  • 对象的别名被赋予新的对象,例如a=24
  • 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的局部变量(全局变量不会)
  • 对象所在的容器被销毁,或从容器中删除对象

3、查看一个对象的引用计数

import sys
a = "hello world"
sys.getrefcount(a)

可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1

有三种情况会触发垃圾回收:

  • 当gc模块的计数器达到阈值的时候,自动回收垃圾
  • 调用gc.collect(),手动回收垃圾
  • 程序退出的时候,python解释器来回收垃圾

解决循环引用的方式:隔代收集

隔代收集:把对象分为三代,一开始,对象在创建的时候,放在一代中,如果在一次一代的垃圾检查中,该对象存活下来,就会被放到二代中,同理在一次二代的垃圾检查中,该对象存活下来,就会被放到三代中。

gc模块里面会有一个长度为3的列表的计数器,可以通过gc.get_count()获取。

例如(488,3,0),其中488是指距离上一次一代垃圾检查,Python分配内存的数目减去释放内存的数目,注意是内存分配,而不是引用计数的增加。例如:

print(gc.get_count()) # (590, 8, 0)
a = ClassA()
print(gc.get_count()) # (591, 8, 0)
del a
print(gc.get_count()) # (590, 8, 0)

3是指距离上一次二代垃圾检查,一代垃圾检查的次数,同理,0是指距离上一次三代垃圾检查,二代垃圾检查的次数。

gc模快有一个自动垃圾回收的阈值,即通过gc.get_threshold函数获取到的长度为3的元组,例如(700,10,10) 每一次计数器的增加,gc模块就会检查增加后的计数是否达到阈值的数目,如果是,就会执行对应的代数的垃圾检查,然后重置计数器

例如,假设阀值是(700,10,10):

当计数器从(699,3,0)增加到(700,3,0),gc模块就会执行gc.collect(0),即检查一代对象的垃圾,并重置计数器为(0,4,0)
当计数器从(699,9,0)增加到(700,9,0),gc模块就会执行gc.collect(1),即检查一、二代对象的垃圾,并重置计数器为(0,0,1)
当计数器从(699,9,9)增加到(700,9,9),gc模块就会执行gc.collect(2),即检查一、二、三代对象的垃圾,并重置计数器为(0,0,

文章参考视频:https://www.bilibili.com/video/BV1Cu411e7Mh?spm_id_from=333.1007.top_right_bar_window_default_collection.content.click

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值