python 内存管理

Python中的内存管理涉及包含所有Python对象和数据结构的私有堆。Python内存管理器在内部确保对此私有堆的管理。需要注意的是,Python堆的管理是由解释器本身执行的,并且用户无法控制它。从源码来看,分为以下几层:

python 内存管理架构

  • level +3:内置类型分配器
  • level +2:python对象分配器
  • level +1:python原生内存分配器
  • level   0:底层通用分配器
  • level -1:特定于os的虚拟内存管理器
  • level -2:物理内存管理器

由上可知,Python 中的对象管理主要位于 +1 ~ +3 层。对于大于512KB(可以设置更改)的对象,使用 +1层中的 Python 原生内存分配器(Python’s raw memory allocator)进行分配,其本质是调用 C 标准库中的 malloc/calloc/realloc/free等函数;对于小于等于 512KB 的对象,使用+2层的Python 对象分配器(Python’s object allocator)实施。对于一些内置类型,如 int/dict/list/string 等,会有单独的针对这些内置类型的分配器实现。比如管理 int 类型就使用一个简单的 free list,这些分配器都位于 +3层。

在Python中,为了解决内存泄露问题,采用了对象引用计数(reference count),并基于引用计数实现自动垃圾回收。借助“标记-清除”机制消除循环引用带来的影响。引入“分代回收”机制减少“标记-清除”所带来的额外操作。

  • 引用计数
# 计数增加  refcnt incr
#define Py_INCREF(op) (
_Py_INC_REFTOTAL _Py_REF_DEBUG_COMMA
((PyObject*)(op))->ob_refcnt++)
#计数减少   refcnt desc
#define _Py_DEC_REFTOTAL _Py_RefTotal--
#define _Py_REF_DEBUG_COMMA ,
#define Py_DECREF(op)

do{

if(_Py_DEC_REFTOTAL _Py_REF_DEBUG_COMMA
--((PyObject*)(op))->ob_refcnt!= 0)
_Py_CHECK_REFCNT(op)

else
_Py_Dealloc((PyObject *)(op));          # refcnt变成0的时候, 会调用_Py_Dealloc

}while(0)

PyAPI_FUNC(void)_Py_Dealloc(PyObject *);

#define _Py_REF_DEBUG_COMMA ,
#define _Py_Dealloc(op) (

_Py_INC_TPFREES(op)_Py_COUNT_ALLOCS_COMMA
(*Py_TYPE(op)->tp_dealloc)((PyObject *)(op)))         # 调用各自类型的tp_dealloc
#endif /* !Py_TRACE_REFS */
# Python基本类型的tp_dealloc, 通常都会与各自的缓冲池机制相关,释放会优先放入缓冲池中(对应的分配会优先从缓冲池取).这个内存分配与回收同缓冲池机制相关
# 当无法放入缓冲池时, 会调用各自类型的tp_free
# 当计数变为0时,使用tp_free函数进行内存销毁的操作
PyTypeObject PyType_Type= {
PyVarObject_HEAD_INIT(&PyType_Type,0)
"type",                 /* tp_name */
...
PyObject_GC_Del,        /* tp_free */
};
  • 内存回收
    • 放入缓冲池:缓存部分反复创建和销除的对象,而非在它们释放后直接从内存删除它们,从而加速下次该对象的创建。
    • 真正销毁,使用PyObject_Del/PyObject_GC_Del对内存进行操作
      • PyObject_Del  不运行析构函数只释放内存。同PyObject_Free
      • PyObject_GC_Del

void
PyObject_GC_Del(void*op)
{
PyGC_Head *g= AS_GC(op);
# 如果跟踪给定对象,则返回true
if(IS_TRACKED(op))                 # IS_TRACKED 涉及标记-清除机制
# 从跟踪链表中移除
gc_list_remove(g);
if(generations[0].count> 0){       # generations 涉及分代回收机制
generations[0].count--;
}
PyObject_FREE(g);                  # PyObject_FREE 涉及python底层内存池机制
}
  • 标记-清除
  • 分代回收
    • 将系统中的所有内存块根据其存活时间划分为不同的集合, 每个集合就称为一个”代”。
    • 一个代就是一个链表, 所有属于同一”代”的内存块都链接在同一个链表中。
    • Python中总共有三个”代”,每个代的threshold值表示该代最多容纳对象的个数。默认情况下,当0代超过700,或1,2代超过10,垃圾回收机制将触发。0代触发将清理所有三代,1代触发会清理1,2代,2代触发后只会清理自己。
    • 垃圾收集的频率随着”代”的存活时间的增大而减小(存活时间越长的对象, 就越不可能是垃圾, 就会减少其收集的频率)

  • id() 查看该对象的内存地址;
  • is 判断两个引用所指的对象是否相同;
  • sys包中的getrefcount()来查看对象的引用次数。需要注意的是,当使用某个引用作为参数,传递给getrefcount()时,参数实际上创建了一个临时的引用。因此,getrefcount()所得到的结果,会比期望的多1。

http://ju.outofmemory.cn/entry/215604

Python 源码阅读:垃圾回收机制

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值