python 内存管理机制

一、引用计数机制
查看对象的引用计数:sys.getrefcount()
引用计数增加
1.对象被创建
2.对象被别的变量引用
3.对象被作为元素,放到容器中(比如被当作元素放在列表中)
4.对象被当成参数传递到函数中

import sys
>>>>li = [] # 创建对象 +1
>>>>li2 = li # 被别的变量引用
>>>>li3 = [li,1] # 作为元素放到容器中
>>>>sys.getrefcount(li) # 对象被当成参数传递到函数中
>4

引用计数减少
1.对象的别名被显式销毁

import sys
>>>>li = [] # 创建对象 +1
>>>>li2 = li # 被别的变量引用
>>>>del li # 对象的别名被显式销毁
>>>>sys.getrefcount(li2) # 对象被当成参数传递到函数中
>2

2.对象的一个别名被赋值给其他对象(例:原来的1=10,被改成a=100,此时10的引用计数就减少了)

import sys
>>>>aa = [11,22]
>>>>bb = aa # 被别的变量引用
>>>>sys.getrefcount(aa) # 对象被当成参数传递到函数中
>3
>>>>bb = 888
>>>>sys.getrefcount(aa)
>2

3.对象从容器中被移除,或者容器被销毁(例:对象从列表中被移除,或者列表被销毁)

import sys
>>>>aa = [11,22]
>>>>bb = aa  # 被别的变量引用
>>>>cc = [11,aa]
>>>>sys.getrefcount(aa)  # 对象被当成参数传递到函数中
>4
>>>>cc.remove(aa)
>>>>sys.getrefcount(aa)
>3

4.一个引用离开了它的作用域(调用函数的时候传进去的参数,在函数运行结束侯,该参数的引用即被销毁)

import sys

x = [1, 2]

def fun(lis):
    print(sys.getrefcount(lis))
  
fun(x)
print(sys.getrefcount(x))

>>>>4
>>>>2

二、数据池与缓存

1.小整数池:Python自动将-5至256范围内的整数缓存到一个小整数池当中,当将这些整数赋值给变量时,并不会重新创建对象,而时使用已经创建好的缓存对象,当删除这些数据的引用时,也不会进行回收
举例:

>>>> a = 1
>>>> b = 1

>>>>print(id(a),id(b))
>2325438224432  2325438224432

2.intern机制
也称字符串驻留池,是针对于字符串内存管理的一种优化处理的机制,其优点是在创建新的字符串对象时,会先在缓存池里面找是否有已经存在的值相同的对象(标识符,即只包含数字、字母、下划线的字符串),如果有则直接拿过来引用,避免频繁的创建和销毁内存,提升效率。
1.ascii码中的单个字符

s1 = 'a'
s2 = 'a'
print(id(s1))
print(id(s2))

>>>>1612197
>>>>1612197

2.标识符,即只包含数字、字母、下划线的字符串

s1 = '12akf_'
s2 = '12akf_'
print(id(s1))
print(id(s2))

>>>>1612197335408
>>>>1612197335408

3.缓存机制
对于同类型的对象引用计数为0时,对象之前所申请的内存并不会马上释放,而会根据相关机制放入缓存中。其优点可以降低频繁的去申请内存、释放内存。

float、in、list等内置类型会缓存80个对象
举例:

li = [12,1]
print(id(li))
del li
l2 = [1]
print(id(l2))

# 内存地址一样
>>>1489156511168
>>>1489156511168

其他类型缓存2个对象:
自己创建一个对象,当del删除对象时,其类型会先判断缓存中有没有此对象,如果没有将其缓存起来,而再次创建同类型的对象时,则会将对象重新初始化给变量。

class Test:
    pass

t = Test()
t2 = Test()
print(id(t), id(t2))

del t
del t2
m = Test()
m2 = Test()
print(id(m), id(m2))

>>>>2514030370720 2514030370768
>>>>2514030370720 2514030370768

元组会根据元组数据的长度,分别缓存元组长度为0-20的对象
三、垃圾回收机制
引用计数为主,标记清除、分代回收机制为辅。
当引用计数为0时,垃圾回收机制会自动将其销毁,回收内存空间。而当多个对象出现循环引用的时候,那这两个对象始终不会销毁,引用计数一直不为0,这样就会导致内存泄漏。

标记清除(Mark—Sweep)算法是一种基于追踪回收(tracing GC)技术实现的垃圾回收算法。它分为两个阶段:第一阶段是标记阶段,GC会把所有的『活动对象』打上标记,第二阶段是把那些没有标记的对象『非活动对象』进行回收
对象回收阈值通过gc.get_threshold()查看:

import gc
print(gc.get_threshold())
>>>(700, 10, 10)

分代回收是一种以空间换时间的操作方式,Python将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,Python将内存分为了3“代”,对应的是3个链表分别为:
第0代:新创建的对象都会分配在第0代链表.当总数达到上限时(700),开始垃圾回收,未被回收的放入下一代链表
第1代:当0代链表回收十次后,第一代链表进行一次回收,未被回收的放入下一代
第2代:当第一代链表回收十次之后,第二代链表进行一次回收,未被回收的不做处理,此链表中的对象是存活时间最久的对象,甚至是存活于整个系统的生命周期内。
们的垃圾收集频率随着对象存活时间的增大而减小,分代回收是建立在标记清除技术基础之上。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

久醉绕心弦,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值