创建

Python内存池

当创建大量消耗小内存的对象时,频繁调用new/malloc会导致大量的内存碎片,致使效率降低。内存池的作用就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够之后再申请新的内存。这样做最显著的优势就是能够减少内存碎片,提升效率。

Python内存池也是金字塔形式
LEVEL+1 层:内置对象 内存池不共享
LEVEL+2 层:< 256KB Python对象分配器
LEVEL+3 层: >256KB C中malloc/realloc
释放内存也是还到内存池中

垃圾回收

引用计数

为0时,就进入垃圾回收队列

引用计数增加:

  • 一个对象被分配一个新的名字
  • 放入一个容器中

引用计数减少:

  • del
  • 容器被销毁或从容器中删除
  • 超出作用域/被重新赋值

循环引用

在容器对象之间存在
a 引用 b
b 引用 a
del 之后 还是都有1

为了针对循环引用, 标记-清除机制

  • 标记阶段,遍历所有的对象,如果是可达的(reachable),也就是还有对象引用它,那么就标记该对象为可达
  • 清除阶段,再次遍历对象,如果发现某个对象没有标记为可达(即为Unreachable),则就将其回收

但是,垃圾回收阶段会暂停整个应用程序,结束后才会恢复运行,为了减少时间,采用分代回收以空间换时间方法提高回收效率

分代回收

分代回收是基于这样的一个统计事实,对于程序,存在一定比例的内存块的生存周期比较短;而剩下的内存块,生存周期会比较长,甚至会从程序开始一直持续到程序结束。生存期较短对象的比例通常在 80%~90%之间。
因此,简单地认为:对象存在时间越长,越可能不是垃圾,应该越少去收集。这样在执行标记-清除算法时可以有效减小遍历的对象数,从而提高垃圾回收的速度,是一种以空间换时间的方法策略。

  • 700=新分配的对象数量-释放的对象数量,第0代gc扫描被触发
  • 第一个10:第0代gc扫描发生10次,则第1代的gc扫描被触发
  • 第二个10:第1代的gc扫描发生10次,则第2代的gc扫描被触发