大家好,我是小眼睛优粥面,上一篇文章和大家简单聊了一聊python垃圾回收中的 “标记清除” 和 “分代回收” 机制,我们用几句话简单总结一下前面我们介绍的内容。
在python内部中自己维护了一个refchain双向环状链表,我们使用程序创造的所有对象都会存到这个链表中,而每一个对象都记录着一个引用计数器的值(ob_refcnt),对象被引用时引用计数器+1,删除引用时引用计数器-1,最后当引用计数器的值变为0的时候,则启动垃圾回收机制,即从双向链表中将该对象删除。但是在python中对于那些有多个元素组成的对象存在循环引用的问题,为了解决这个问题python又引用了标记清除和分代回收机制。但是如果就这样完事了,那岂不是太简单,python源码内部在上述的流程中还做了一些优化,那就是:缓存机制。今天我们就来聊一聊这块的内容。
欢迎大家交流分享(码字不易,希望大家标明出处),有不对的地方请大家指正,也希望大家关注我的微信公众号 “记不住先生和忘不了小姐”,里面不光有 “记不住” 的技术还有那 “忘不了” 的情怀,万分感谢啦^ ^
Python中缓存机制主要分为两大类,分别是 “缓存机制” 和 “free_list机制”,缓存机制有可细分为:小数据池和驻留机制,我们详细来看一下。
1. 小数据池(small_ints 和 unicode_latin1)
所谓小数据池,就是为了避免重复创造和销毁一些常见对象,python在其内部会自己维护一个缓存资源的操作,我们看这么一个代码(python版本3.7.6)。
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> p1 = 1
>>> p2 = 1
>>> print(id(p1))
140734330597648
>>> print(id(p2))
140734330597648
>>> p3 = 257
>>> p4 = 257
>>> print(id(p3))
559876634128
>>> print(id(p4))
559876633520
我们都知道,正常情况下,如果我们运行python程序的时候是先会先向内存去申请一块内存空间,用来存储我们的数据。每次变量的赋值理论上都会开辟新的内存空间,而程序在内存中存储数据是按照空间连续去存储的,所以按道理变量p1和变量p2应该指向不同的内存地址,但我们这上面为什么是同一个呢。
这是因为python为了节省资源,避免重复创建和销毁一些常见的对象,它在启动解释器的时候自动创建了一些默认的 “缓存池”,对于部分小整型和字符型执行缓存机制。即将这些对象进行预先创建,不会为相同的对象分配多个内存空间,这些数据包括:
在解释器启动的时候,python会自动创建以下小数据池,如果是不同代码块中的两个变量,并在此范围内,那么它们具有相同的id值,即重复使用这个范围的内容时,不会重新开辟内存空间,具体内容如下:
(1)small_ints链表:存储 -5,-4,-3,...,256 范围内(-5 <= value < 257)的整数。
(2)unicode_latin1[256]链表:存储所有的 ascii 字符,以后使用时就不再反复创建。