内存管理机制
所有公司都会遇到两个最难处理,最恶心的问题:
- 高并发问题
- 内存泄漏问题(例:比如一个大袋子可以装100斤大米,但是却装了200斤大米。虽然我们可以在换个袋子,但是袋子里的大米却不好捡起来)
- 所以公司一般都会有一套容灾系统:
- 程序崩了,瞬间切换到另一台服务器让它跑起来,数据一般都不会放在同一台服务器上
- 我有1个G的内存,一个游戏需要800M的内存,其他的需要300M的内存,它们都互相竞争资源,其写的不让写,游戏想写写不进去,就崩了。现在的程序就是内存快满了,就会回收一些你不用的,把空间省下来。
- 所以公司一般都会有一套容灾系统:
- python的就是垃圾回收机制
垃圾回收机制
在python源码中,ob_refcnt记录了对象的引用次数。当一个对象有新的应用时,ob_refcnt加一,引用它的对象被删除时,ob_refcnt=0,这个对象的生命就结束了,这时,垃圾回收机制就会启动将这个对象回收。
类执行完毕后会自动调用__del__方法,进行垃圾回收
什么时候回收(回收时机):
1、隔断时间自动回收
2、内存不够了回收
3、主动调用gc
gc.collect()
python是引用计数为主,标记清除+分代回收为辅
程序如何判断是否是垃圾:
1、引用计数
2、标记清楚+分代回收
引用计数
优点:
- 简单、易可用
- 实时性高,只要对象引用计数为0,对象就会被销毁,内存被释放,回收内存的时间平摊到了平时
缺点:
* 为了维护引用计数消耗了很多资源
* 循环引用,循环引用导致内存泄漏,例:
>>> class lia(list):
... def __del__(self):
... print('a销毁')
...
>>> class lib(list):
... def __del__(self):
... print('b销毁')
>>> a= lia()
>>> b = lib()
>>> a.append(b) # 循环引用
>>> b.append(a)
# 会发现没有触发del方法
>>> a = 2
>>> b = 3
这样就会导致list1和list2的引用计永远大于0,除非手动操作,他们也不可能被GC回收,但如果你手动将其释放回收,那么GC机制岂不是形同虚设,针对这种情况,python引入了标记清除和分代回收机制作为补充
标记清除
- 从变量出发,看你这个变量用到了哪些东西,用到了就留着。如果从头到尾发现某些数据没有被使用过,这个数据就是垃圾。
- 解决的就是循环引用的问题
- 弊端:浪费时间(执行速度比较慢),cpu资源
标记清除的原理:
标记清除可以处理这种循环引用的情况,它分为两个阶段
- 第一阶段,标记阶段
- GC会把所有活动对象打上标记,这些活动的对象就如同一个点,他们之间的引用关系构成边,最终点边构成了一个有向图
- 第二阶段,搜索清除阶段
- 从跟对象(root)触发,沿着有向边遍历整个图,不可达的对象就时需要清理的垃圾对象,这个根对象就是全局对象,调用栈,寄存器
分代回收
-
解决的就是标记清楚所引发的问题
-
分代回收建立标记清楚的基础之上,是一种以空间换时间的操作方式。标记清楚可以回收循环引用的垃圾,但是,回收的频次是需要控制的,如果时时刻刻做标记清楚,可以想象,python的程序会慢成什么样子。
-
分代回收,根据内存中对象的存活时间将他们分为3代,新生的对象放入到0代,如果一个对象能在第0代的回收过程中存活下来,GC就会将其放入到1代中,如果1代里的对象在第1代的垃圾回收过程中存活下来,则会进入到第2代。
触发机制
import gc
print(gc.get_threshold()) # (700,10,10)
- 当分配对象的个数减去释放对象的个数的差值大于700时,就会产生一次0代(青年代)回收
- 10次0代回收会导致一次1代(中年代)回收
- 10次1代回收会导致一次2代(老年代)回收
对于0代的对象来说,他们很可能就被使用一次,因此需要经常被回收
经过第0代的对象来说,他们很可能就被使用一次,因此需要经常被回收。
经过一轮一轮的回收后,能过存活着成为第二代的对象,必然时那些使用频繁的对象,而且他们以及存活很久的时间了,大概率的,还会存活很久,因此,2代回收的就不那么频繁
你可以设置这三个阈值,来改变分代回收的触发条件
import gc
# 设置使0代和2代的回收更加频繁
gc.set_threshold(600, 10, 5)
print(gc.get_threshold())
例如:
有1000个对象·,销毁了1000个对象,还有900个对象,大于700,担心900个对象里面有大量的垃圾对象,所以就进行一次0代回收,在0代回收存活的对象,一般还能存活很久。在0代回收的对象,就会放入到1代当中。当进行10次1代回收之后,就会进入2代回收