一. 对象池
- 小整数对象池
1)整数在程序中的使用非常广泛,python为了优化速度,使用了小整数对象池,避免为整数频繁的申请和销毁内存。
2) python 对小整数的定义是[ -5 , 257) ,这些整数对象是提前建立好的,不会被垃圾回收。在一个python程序中,所有位于这个范围内的整数使用的都是同一个对象。
- 大整数池
每一个大整数,均创建一个新的对象。
itern机制
string iterning (字符串驻留): 他通过维护一个字符串常量池(string item pool ),从而试图只保存唯一的字符串对象,达到既高效又节省内存地处理字符串的目的。
在创建一个新的字符串对象后,python先比较变量池中是否相同的对象(iterned),有的话则指向已有的对象,并减少新对象的指、、针,新对象由于没有引用计数,就会被垃圾回收机制回收掉,释放出内存。
字符串(含有空格),不可修改,没开启 intern 机制,不共用对象,引用计数为0 ,销毁。
内存溢出与内存泄露:
内存溢出(out of memory ): 指程序在申请内存时,没有足够的内存空间供其使用。
出现内存溢出的情况:比方说,定义20字节大小的内存空间,却写入21个字节的数据。当发生内存溢出时,程序将无法进行,强制终止。
内存泄露(memory leak ): 是指程序在申请内存后,无法释放已申请的内存空间,一次内存泄露可以忽略,但内存泄露堆积后果严重,无论多少内存,迟早会被占光。如果发生内存泄露,那么可用的内存会逐渐减少,从而降低性能。
解决方案:为了防止内存泄露,GC(Garbage Collection )会拼命地将垃圾回收再利用。
垃圾回收机制: python 采用是引用计数机制为主,标记——清除和分代收集两种机制为辅的策略
引用计数机制:
1) 定义:Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
2) 在python中每一个东西都是对象,它们的核心就是结构体: PyObject
当引用计数为0 时,该对象的生命就结束了,即:会被当成垃圾清理了。
引用计数就是:当一个对象不存在时,会创建对象。当一个对象之前就存在,再次引用时引用计数会加一
引用计数+1 的情况:
1) 对象被创建 eg. a = 12
2) 对象被引用 eg . b = a
3) 对象作为参数,传入到一个函数中 eg. func(a)
4)对象作为一个元素,存储在容器中 eg. list = [a ,a ,a]
引用计数 - 1 的情况:
1) 对象的别名被显示性销毁 eg . del a
2) 对象的别名被赋予新的对象 eg . a = 30
3) 一个对象离开它的作用域 eg . 函数执行完毕时,func 函数的局部变量(全局变量不会)
4) 对象所在的容器被销毁,或者从容器中删除对象。
引用计数的优点:
1)简单
2) 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定时机。实时性的好处:处理回收内存的时间分摊到了平时。
引用计数的缺点:
1)维护引用计数消耗资源
2) 循环引用
eg .
import time
import gc
# 关闭python自动实现的垃圾回收机制;
gc.disable()
while True:
time.sleep(0.0003)
# 申请两个内存空间, 变量list1和变量list2分别指向不同的内存空间, 引用计数全为1;
list1 = []
list2 = []
# 在容器list1里面存储了list2, list2的引用计数加1;
list1.append(list2)
# 在容器list2里面存储了list1, list1的引用计数加1;
list2.append(list1)
# 删除list1和list2
del list1
del list2
这是循环引用的一个例子,list1 和 lsit2 相互引用,如果不存在其他对象对它们的引用,list1 和 list2 的引用计数也仍然为1 , 所占用的内存永远无法被回收,这将致命的。最后系统可能就会崩溃。
标记清除: 在python中,清除算法由标记阶段和清楚阶段。标记阶段是把所有活动对象都做上标记的阶段。清除阶段是把那些没有标记的对象,也就是非活动对象回收阶段。通过这两个阶段,就可以令不能利用的内存空间重新得到利用。
如果被标记的对象是存活的,剩下的未标记的对象只能是垃圾。这就是意味着我们的代码不再会使用它。
清除这些无用的垃圾对象,把它们送回到可用列表。
分代收集:
分代垃圾回收在对象中导入了“年龄”的概念,通过优先回收容易成为对象,提高垃圾回收的效率。
分代垃圾回收:
1) 分代垃圾回收中把对象分类成几代,针对不同的代使用不同的GC算法,因此把刚生成的对象称为新生代对象,达到一定年龄的对象则成为老年代对象。
2) 新生代GC 将存活了一定次数的新生代对象当作老年代对象来处理。我们把类似于这样的新生代对象的情况称为晋升。
3) 老年代对象很难成为垃圾,因此减少执行GC的频率,从而提高效率。
年龄的区分:对象的年龄:每经过一次 GC 后活下来的对象年加一岁。