今天和大家探讨一下Python内存管理机制和调优手段.话不多说,直接上干货:
那么Python的内存管理机制都有什么呢?
1 . 引用计数
2 . 垃圾回收
3 . 内存池
调优手段也都三大金刚:
1. 手动垃圾回收
2. 调高垃圾回收阈值
3. 避免循环引用
好啦,现在开始开车了,大家坐稳啦!
垃圾回收机制引用计数在最基础也是最常见的,为什么呢?
引用计数:
引用计数是一种非常高效的内存管理手段,当一个Python对象被引用时其引用计数增加1,当其不再被一个变量引用时则计数
减一,当引用计数为0时对象被删除.
垃圾回收也是有三大干将的,他们就是引用计数,标记清除, 分代回收.
1. 引用计数:
引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集计数.当Python的某个对象的引用计数降为0
时,说明没有任何引用指向该对象,该对象就成为要被回收的的垃圾了.比如某个新建对象,它被分配给某个引用,对象的引用计数变为
1.如果引用被删除,对象的引用计数为0,那么该对象就可以被垃圾回收.不过如果出现循环引用的话,引用计数机制就不再起有效的
作用了.
2. 标记清除:
引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集计数.当Python的某个对象的引用计数降为0
时,说明没有任何引用指向该对象,该对象就成为要被回收的的垃圾了.比如某个新建对象,它被分配给某个引用,对象的引用计数变
为 1.如果引用被删除,对象的引用计数为0,那么该对象就可以被垃圾回收.不过如果出现循环引用的话,引用计数机制就不再起有效
的作用了.
3. 分代回收:
从前面"标记-清除"这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量
是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收待来的额外操作就少;反之,当需回收的内存块越
少时,垃圾检测就将比垃圾回收带来更少的额外操作.
举个例子:
当某些内存块M经过了3次垃圾收集的清洗之后还存活时, 我们就将内存块M划到一个集合A中去, 而新分配的内存都划分
到集合B中去.当垃圾回收开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进
行, 这就使得垃圾收集机制需要处理的内存少了, 效率自然就提高了.在这么过程中,集合B中的某些内存块由于存活时间长而会被转
移到集合A中, 当然,集合A中实际上也存在一些垃圾,这么垃圾的回收会因为这种分代的机制而被延迟.
最后再来瞅瞅压轴大家伙吧!它就是'内存池'!
一提到池的大家都会感觉很高大上吧,池的概念是先开辟好一个空间,提高代码的运行效率,不会在运行的时候才拿到内存.
那么现在我们来欣赏一下内存池的神秘面纱吧!
1.python的内存机制呈现金字塔形状,-1, -2层主要有操作系统进行操作;
2. 第0层是c中的malloc, free 等内存分配和释放函数进行操作
3.第一层和第二层是内存池,有python的接口函数 PyMem_Malloc函数实现, 当对象小于256k时有该层直接分配内存;
4. 第3层是最上层, 也就是我们对Python对象的直接操作
Python在运行期间会大量的执行malloc 和 free的操作, 频繁地在用户态和核心态之间进行切换, 这将严重影响Python的执
行效率.为了加速Python的执行效率, Python引入了一个内存池机制,用于管理对小块内存的申请和释放.
Python内部默认的小块内存与大块内存的分界点定在256个字节, 当申请的内存小于256字节的时候,PyObject_Malloc会在
内存池中申请内存;当申请的内存大于256字节时,PyObject_Malloc的行为将蜕变为malloc的行为.当然,通过修改Python源代码,我
们可以改变这个默认值,从而改变Python的默认内存管理行为.