python的内存管理机制

引用

python 中的赋值语句 a = 100 代表。给对象100添加一个引用a
b = a 给对象a添加一个引用b
对象保存在内存中,同一个对象,即其所有的引用在内存中的位置都是一样的
我们可以使用id()函数查看对象的内存地址,或者使用is关键字判断两个引用是否指向统一对象

a = 100
b = a
print(id(a))
print(id(a))
print(a is b)


# 1485061936
# 1485061936
# True

在python一般对象是在内存中新建的,例如a = [1, 2, 3] , 首先是在内存中创建一个对象[1, 2, 3],然后a指向该对象。
对于整数和短小的字符,Python都会缓存这些对象,以便重复使用。当我们创建多个等于1的引用时,实际上是让所有这些引用指向同一个对象。

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

c = 'girl'
d = 'girl'
print(a is b)
# True

f = [1, 2, 3]
g = [1, 2, 3]
print(f is g)
# False

引用计数

引用计数是只python中每一个指向该对象的引用的总数。
每当有新的引用指向对象时,对象引用计数+1
当引用指向其他地方,或者引用被删除时,引用计数-1

我们可以通过getrefcount()函数来查看对象的引用计数,调用该函数时也会增加一个对像的引用,得到的结果回比原本的引用计数多一个。

from sys import getrefcount

a = [1, 2, 3]
print(getrefcount(a))

b = a
print(getrefcount(b))

对象清理

当某个对象的引用计数减到0时,就没有任何变量能够调用改对象,那么这个对象就可以被回收,清空所在内存。
回收内存是费时费力的事情,如果过于频繁则运行效率会特别低。所以python会定期清理内存。
当Python运行时,会记录其中分配对象(object allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,即大量的对象被创建,占据了过多的内存,垃圾回收才会启动。

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

通过gc.get_threshold()方法可以看出,700就是这个阈值。
我们也可以手动设置这个阈值set_threshold()
或者直接手动回收gc.collect()

分代回收

python认为,存在时间久的对象更有用,更不可能是垃圾。因此引入分代回收机制。
首先,所有新建的对象都是第0代,当某经过一次回收后保留下来,那么该对象就数以第1代。当对第1代的回收后,留下来的对象就是第二代。
gc.get_threshold()返回的元组中的10,10 就是指回收10次第0代对象才会回收一次第1代对象,回收10次第1代对象后,才会回收第2代对象。
这个也可以通过gc.get_threshold()方法手动设置。

引用环回收

如果存在引用环,引用计数无法减到0,使用上面的机制就一直无法回收引用环
例如:

a = []
b = [a]

a.append(b)

del a
del b

虽然我们删除了a, b但是两个对象相互引用成为一个孤立的环引用计数一直不为0,就不会被垃圾回收

对于这样的引用环,python为了回收这样的引用环,Python复制每个对象的引用计数,可以记为gc_ref。假设,每个对象i,该计数为gc_ref_i。Python会遍历所有的对象i。对于每个对象i引用的对象j,将相应的gc_ref_j减1。

在结束遍历后,gc_ref不为0的对象,和这些对象引用的对象,以及继续更下游引用的对象,需要被保留。而其它的对象则被垃圾回收。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值