python内存管理机制

对象池

python内存管理机制是什么?
1). 由于python中万物皆对象,内存管理机制就是对象的存储问题,Python会分 配一块内存空间去存储对象。
2) 对于整数和短小的字符等,python会执行缓存机制,即将这些对象进行缓存, 不会为相同的对象分配多个内存空间
3). 容器对象,如列表、元组、字典等,存储的其他对象,仅仅是其他对象的引 用,即地址,并不是这些对象本身

小整数对象池

1). 整数在程序中的使用非常广泛,Python为 了优化速度,使用了小整数对象池,避免为整数 频繁申请和销毁内存空间。
2). Python对小整数的定义是[-5,257) 这些整数对象是提前建立好的,不会被垃圾 回收。在一个Python的程序中,所有位于这 个范围内的整数使用的都是同一个对象.
通俗理解: :[-5,257) 此范围内的整数如果有两个相同的整数赋值会指向同一个地址

>>> a = 1
>>> id(a)
139883638752032
>>> b = 1
>>> id(b)
139883638752032
>>> c = 257
>>> d = 257
>>> id(c), id(d)
(139883633580400, 139883633580432)
>>> e=-5;f=-5
>>> id(e), id(f)
(139883638751840, 139883638751840)

字符串驻留机制

string interning(字符串驻留): 它通过维护一个字符串常量池(string intern pool),从而试图只保存唯一的字符串对象,达到既高效又节省内存地处理字符串的目的。
创建新的字符串对象时,Python 先比较常量池中是否有相同的对(interned),有 的话则将指针指向已有对象,并减少新对象的指针,新对象由于没有引用计数,就会被垃圾回收机制回收掉,释放出内存。
字符串(含有空格),不可修改,没开启intern机制,不共用对象,引用计数为0,销毁。
通俗理解: 相同字符串对应相同地址。相同字符串(含有空格)对应不同地址。

>>> a = 'hello'
>>> b = 'hello'
>>> id(a), id(b)
(139883511138480, 139883511138480)
>>> c = 'pythonchjdshfcejhfkjrehfkjrehfkjrehfregjrkhgkjrg'
>>> d = 'pythonchjdshfcejhfkjrehfkjrehfkjrehfregjrkhgkjrg'
>>> id(c),id(d)
(139883633099360, 139883633099360)
>>> a = 'a b'   #字符串(含有空格),不可修改,没开启intern机制,不共用对象,引用计数为0,销毁。
>>> b = 'a b'
>>> id(a), id(b)
(139883511138608, 139883511138544)

垃圾回收机制

内存溢出 out of memory,是指程序在申请内存时,没有足够的内存空间供其使用。 比方说,定义了20个字节大小的内存空间,却写入了21个字节的数据。
内存泄露 memory leak 是指程序在申请内存后,无法释放已申请的内存空间。 若内存泄露堆积, 内存逐渐减少,从而降低性能。
memory leak会最终会导致out of memory。
垃圾回收机制使用原因
为了防止内存泄露. 对编程语言来说,GC 就是一个无名英雄,拼命地将垃圾回收再利用。 Python采用的是引用计数机制为主,标记-清除和分代收集两种机制为辅的垃圾回收策略。

引用计数机制

GC 原本是一种“释放怎么都无法被引用的对象的机制”。那么人们自然而然地就会想 到,可以让所有对象事先记录下“有多少程序引用自己”。让各对象知道自己的“人气指 数”,从而让没有人气的对象自己消失,这就是引用计数法(Reference Counting).
python里每一个东⻄都是对象,它们的核心就是结构体: PyObject。
当引用计数为0时,该对象生命就结束了。
引用计数器工作机制
(1)一个对象会记录着引用自己的对象的个数,每增加一个引用,个数+1,每减 少一个引用,个数-1

  • 导致引用计数+1的情况:
    1). 对象被创建,例如a=23
    2). 对象被引用,例如b=a
    3). 对象被作为参数,传入到一个函数中,例如func(a)
    4). 对象作为一个元素,存储在容器中,例如list1=[a,a]
>>> # 1). 对象被创建,例如a=23
...
>>> name = 'fentiao'
>>>
>>> # 2). 对象被作为参数,传入到一个函数中
...
>>> import sys
>>> sys.getrefcount(name)
2
>>> # 3). 对象被引用,例如b=a
...
>>> cat_name = name
>>> sys.getrefcount(name)
3
>>> # 4). 对象作为一个元素,存储在容器中,例如list1=[a,a]
...
>>> l = [name, 'hello', 'python']
>>> sys.getrefcount(name)
4
  • 导致引用计数-1的情况:
    1). 对象的别名被显式销毁,例如del a
    2). 对象的别名被赋予新的对象,例如a=24
    3). 一个对象离开它的作用域,例如f函数执行完毕时,func函数中的
    局部变量(全局变量不会)
    4). 对象所在的容器被销毁,或从容器中删除对象
>>> # 1). 对象的别名被显式销毁,例如del a
...
>>> del cat_name
>>> sys.getrefcount(name)
3
>>> # 2). 对象的别名被赋予新的对象,例如a=24
>>> name1 = name
>>> sys.getrefcount(name)
4
>>> name1 = 'hello'
>>> sys.getrefcount(name)
3
>>> # 4). 对象所在的容器被销毁,或从容器中删除对象
...
>>> l
['fentiao', 'hello', 'python']
>>> del l[0]
>>> sys.getrefcount(name)
2

(2)查看引用对象个数的方法:导入sys模块,使用模块中的getrefcount(对象)方 法,由于这里也是一个引用,故输出的结果多1
(3) 引用计数器机制:利用引用计数器方法,在检测到对象引用个数为0时,对普通 的对象进行释放内存的机制
优点:
1). 简单
2). 实时性:一旦没有引用,内存就直接释放了。不用像其他机制等到特定 时机。实时性还带来一个好处:处理回收内存的时间分摊到了平时。
缺点:
1), 维护引用计数消耗资源
2). 循环引用

list1=[]
list2=[]
list1.append(list2)
list2.append(list1)

list1与list2相互引用,如果不存在其他对象对它们的引用,list1与list2的引用计数也仍然为2,所占用的内存永远无法被回收,这将是致命的。 对于如今的强大硬件,缺点1尚可接受,但是循环引用导致内存泄露,注定python 还将引入新的回收机制。(标记清除和分代收集)

标记-清除机制

如它的字面意思一样,GC 标记 - 清除算法由标记阶段和清除阶段构成。标记阶段是 把所有活动对象都做上标记的阶段。清除阶段是把那些没有标记的对象,也就是非活动对 象回收的阶段。通过这两个阶段,就可以令不能利用的内存空间重新得到利用。如果说被标记的对象是存活的,剩下的未被标记的对象只能是垃圾,这意味 着我们的代码不再会使用它了,清除这些无用的垃圾对象,把它们送回到可用列表。

分代回收机制

分代垃圾回收(Generational GC)在对象中导入了“年龄”的概念,通过优先回收容 易成为垃圾的对象,提高垃圾回收的效率。
新生代对象和老年代对象:
1). 分代垃圾回收中把对象分类成几代,针对不同的代使用不同的 GC 算法,我们把刚生成 的对象称为新生代对象,到达一定年龄的对象则称为老年代对象。
2). 新生代 GC 将存活了一定次数的新生代对象当作老年代对象来处理。我们把类似于这 样的新生代对象上升为老年代对象的情况称为晋升(promotion)。
3). 老年代对象很难成为垃圾,所以我们对老年代对象减少执行 GC 的频率, 从而提高效率。
gc模块提供操作垃圾回收的接口,包括禁用gc,调整回收频率,配置debug选项, 同时提供对无法释放内存对象的访问权。

# 1). 分代回收的频率
>>> gc.get_threshold()
(700, 10, 10)
>>> gc.set_threshold(700, 90, 90)
KeyboardInterrupt

# 2). 垃圾回收机制是否开启
>>> gc.isenabled()
True
>>> gc.disable()
>>> gc.isenabled()
False
>>> gc.enable()
>>> gc.isenabled()
True
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值