在python中创建对象的时候,首先会去申请内存地址,然后对这个对象进行初始化,所有的对象都会维护在一个叫做 refachain
的双向循环链表中,每个数据都保存如下信息:
引用计数增加:
上面这么描述可能有写抽象,下面我们通过实例具体查看一下
>>> a = 1000 >>> print(id(a)) 140728749462288
首先当我们创建一个变量a的时候,此时python解释器会给a这个变量分配一个内容地址,我们可以看到上方a的内存地址是 140728749462288
。
那么假设现在我们现在设置b 的a,然后使用 sys.getrefcount(a)
,查看这个a这个对应的引用计数,我们可以看到是3。
>>> a = 1000 >>> b = a >>> sys.getrefcount(a) 3
为什么这里会变成3了,因为当我们a赋值一个变量时,此时引用计数是1次,然后我们使用b赋值等于a时,此时引用计数应该是2次,之所以是3次是因为 sys.getrefcount(a)
自身是一个函数,那么当我们 对象被当成参数传递进函数中
,因此引用计数为3。
下面我们在来看一个非常有意思的现象:
>>> a = 1000 >>> b = 1000 >>> print(id(a)) 2334204996144 >>> print(id(b)) 2334204997136
首先,我们分别定义 a、b两个变量,此时设置的变量值是一致的,都是1000,我们去查看python底层分配的内存地址,可以看到他们的内存地址是不一样的。
那么下面我们将a和b的变量值,都改成1,再来看看:
>>> a = 1 >>> b = 1 >>> print(id(a)) 140728749459120 >>> print(id(b)) 140728749459120
那么我们来思考一下,为什么创建了两个不同的对象,但是内存地址却是一样的呢?
是因为python解释器底层会判断当我们的变量值为 -5 到 255 之间的值,是属于常用的数据,那么这些数据python解释器会把共同值的变量,指向同一个内存地址。其中包括ASCII码中的内容,这么做的目的非常简单,假设我们1这个值,被非常多的变量所引用,如引用一万次,如果不这么处理,那么python会非常1w个内存空间,这样就会造成非常大的资源消耗。
那么此时假设我们的变量值包含数字、字母和符号,我们来查看一下他具体的内存空间分配
>>> a = 'acb23?' >>> b = 'acb23?' >>> print(id(a)) 2334205039216 >>> print(id(a)) 2334205039216
可以看到他们的内存地址也是一样的。这里我们需要了解一下 intern机制
。
intern机制
:它的优点是,在创建新的字符串对象时,会先在缓存池里面找是否有已经存在的相同值的对象(标识符、字母、下划线的字符串),如果有,则直接拿过来(引用),避免频繁的创建和销毁内存,提升效率。
引用计数的减少: