垃圾回收
目录:1.对象池
2.垃圾回收:计数机制
3.垃圾回收:标记-清楚
4.垃圾回收:分代收集
5.gc模块
小整数对象池:
1)整数在程序中的使用非常广泛,Python为了优化速度,使用了小整数对象池,避免为整数频繁申请和销毁内存空间。
2)Python对小整数的定义是[-5,257]这些整数对象是提前建立好的,不会被垃圾回收。在一个Python的程序中,所有位于这个范围内的整数使用的都是同一个对象。
大整数对象池:
1)每一个大整数,均创建一个新的对象。
itern机制
string interning(字符串驻留):它通过维护一个字符串常量池(string intern pool),从而试图只保存为字符串对象,达到即高效又节省内存的处理字符串的目的。
在创建一个新的字符串对象后,Python先比较常量池中是否有相同的对象(interned),有的话则将指针已有对象,并减少新对象的指针,新对象由于没有引用计数,就会被垃圾回收机制收掉,释放出内存。
字符串(含有空格)不可修改,没开启inern机制,不共用对象,引用计数为0,销毁。
垃圾回收机制----内存溢出与内存泄漏
1.内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用,出现out of memory;比方说,定义了20个字节大小的内存空间,却写入了21个字
节的数据。通俗的说,就是内存不够,没办法支持当前程序。当发生内存溢出时,程
序将无法进行,强制终止。
2.内存泄漏 memory leak,是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄漏危害可以忽略,但内存泄漏堆积后果很严重,无论多少内存,迟早会被占光。如果发生内存泄漏,那么可用内存会逐渐减少,从而降低性能。
memory.leak会最终会导致out of memory!
为什么需要Garbage collection?
为了防止内存泄漏,对编程语言来说,GC就是一个无名英雄,默默地做着贡献。打个比方,天鹅在水面优雅地游动时,实际上脚蹼却在水下拼命的划水。GC也是如此。在由编程语言的美丽的源代码这片水下,GC在拼命地将垃圾回收再利用。
Python采用的时引用计数机制为主,标记-清除和分代收集两种机制为辅的策略
引用计数:
GC原本是一种“释放怎么都无法被引用的对象的机制”。那么人们自然而然地就会想到,可以让所有对象事先记录下“有多少程序引用自己”。让各对象知道自己的“人气指数”,从而让没有人气的对象自己消失,这就是引用计数法
python里每一个东西都是对象,它们的核心就是结构体:PyObject
当引用计数为0时,该对象生命就该结束了
导致引用计数+1的情况
1)对象被创建,例如a=23
2)对象被引用,例如b=a
3)对象被作为参数,传入到一个函数中,例如func(a)
4)对象作为一个元素,存储在容器中,例如list1=[a,a]
导致引用计数-1的情况
1)对象的别名被显式销毁,例如def a
2)对象的别名被赋予新的对象,例如a=24
3)一个对象离开它的作用域,例如f函数执行完毕时func函数中的局部变量(全局变量不会)
4)对象所在的日哦能勾起被销毁,或从容器中删除对象。
优点:1)简单 2)实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定世纪。实时性还带来一个好处:处理回收内存的时间分摊到了平时 。
缺点:1)维护引用计数消耗资源 2)循环引用
循环引用:
list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用
计数也仍然为1,所占用的内存永远无法被回收,这将是致命的。 对于如今
的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python还将
引入新的回收机制。(标记清除和分代收集)
标记清除:如它的字面意思一样,GC 标记 - 清除算法由标记阶段和清除阶段构成。标记阶段是把所有活动对象都做上标记的阶段。清除阶段是把那些没有标记的对象,也就是非活动对象回收的阶段。通过这两个阶段,就可以令不能利用的内存空间重新得到利用。
如果说被标记的对象是存活的,剩下的未被标记的对象只能是垃圾,这意味着我们的代码不再会使用它了。
清除这些无用的垃圾对象,把它们送回到可用列表
分代收集:分代垃圾回收在对象中导入了“年龄”的概念,通过优先回收容易成为垃圾的对象,提高垃圾回收的效率。
什么是分代垃圾回收?
新生代对象和老年代对象:
1)分代垃圾回收中把对象分类成几代,针对不同的代使用不同的GC算法,我们把刚生成的对象称为新生代对象,到达一定年龄的对象称为老年代对象。
2)新生代GC将存活了一定次数的新生代对象当作老年代对象来处理。我们把类似于这样的新生代对象上升为老年代对象的情况称为晋升。
3)老年代对象很难成为垃圾,所以我们对老年代对象减少执行GC的频率,从而提高效率。