测开之面向对象进阶篇?《内存管理机制》

2021/10/15 7:17:21

本文主要是介绍测开之面向对象进阶篇?《内存管理机制》,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

内存管理机制

    • 内存管理机制
    • 引用计数机制

内存管理机制

在python中创建对象的时候,首先会去申请内存地址,然后对这个对象进行初始化,所有的对象都会维护在一个叫做 refachain 的双向循环链表中,每个数据都保存如下信息:

  • 链表中数据前后数据的指针
  • 数据的类型
  • 数据值
  • 数据的引用计数
  • 数据的长度(list,dict…)

在这里插入图片描述

引用计数机制

引用计数增加:

  1. 对象被创建
  2. 对象被别的变量应用(另外起了一个名字)
  3. 对象被作为元素,放在容器中(比如被当着元素放在列表或者字典中)
  4. 对象被当成参数传递进函数中

上面这么描述可能有写抽象,下面我们通过实例具体查看一下

>>> 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机制:它的优点是,在创建新的字符串对象时,会先在缓存池里面找是否有已经存在的相同值的对象(标识符、字母、下划线的字符串),如果有,则直接拿过来(引用),避免频繁的创建和销毁内存,提升效率。

引用计数的减少:

  1. 对象的别名被显式的销毁
  2. 对象的一个别名被赋值给其他对象(例如:原来的a=10,我们改成a=100,那么此时10的引用计数就减少了)
  3. 对象从容器中移除,或者容易被销毁(例:对象从列表中移除,或者列表被销毁)
  4. 一个引用离开了他的作用域(调用函数的时候传进去的参数,在函数运行结束后,该参数的引用被销毁)


这篇关于测开之面向对象进阶篇?《内存管理机制》的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程