tyltr技术窝

python的内存管理机制主要包括引用计数、垃圾回收、内存池三方面组成。

引用计数#

Python的内存管理是通过对象的引用计数器来实现的。
对象的创建会将引用计数器加1,被引用一次则引用计数器就会加1,反之解除引用时,则引用计数器就会减1。
当Python对象的引用计数器为0的时候,则这个对象就会被回收和释放。

python源代码,一切对象都是以PyObject结构体为基础的。

Include/object.h

1
2
3
4
5
6
7
typedef struct _object {
_PyObject_HEAD_EXTRA

// 引用计数
Py_ssize_t ob_refcnt;
struct _typeobject *ob_type;
} PyObject;

所有的对象之中,都有引用计数。

引用计数实现简单,但是有一个致命问题:循环引用。即对象A引用对象B,对象B引用对象A。

垃圾回收#

标记-清除#

为了解决循环引用的问题,所有引入了标记清除算法。但此算法的也存在严重的问题就是STWstop the world
标记时,所有的线程都会被挂起。

分代回收#

标记清除已经可以彻底的清除垃圾了。但每次运行都要stw。怎么进行优化呢?
分代回收的思想就是对象存在时间越长,越可能不是垃圾,应该越少去收集。
也就是说对于根据生存时间将对象划分为不同的代,每代的回收频率不同。时间长的回收频率越少,
也就相对提升了gc的性能了

垃圾回收时机#

  • 调用gc.collect()
  • GC达到阀值时
  • 程序退出时

内存池#

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

针对小对象,就是大小小于256kb时,会在内存池中申请内存空间;
当大于256kb,则会直接执行 new/malloc来申请新的内存空间。