标签:def 就会 通过 解决 不同 占用 data 双向链表 有向图
在Python
源码中,每一个对象都是一个结构体表示,都有一个计数字段。
typedef struct_object { int ob_refcnt; struct_typeobject *ob_type; } PyObject;
PyObject
是每个对象必有的内容,其中ob_refcnt
就是作为引用计数。当一个对象有了新的引用时,它的ob_refcnt
就会增加,引用它的对象被删除时则减少。一旦对象的引用计数为0,该对象立即被回收,占用空间就会被释放。
优点:
简单易用
实时性好,一旦没有引用就会被立即释放
缺点:
需要额外空间去维护引用计数
不能解决对象的循环引用
循环引用是指两个对象相互引用且没有外部变量引用其中任何一个,导致引用链形成一个环。
>>> a = {} # 对象a的引用计数为1 >>> b = {} # 对象b的引用计数为1 >>> a[‘b‘] = b # b的引用计数增加1 >>> b[‘a‘] = a # a的引用计数增加1 >>> del a # a的引用计数减少1,最后a的引用为1 >>> del b # b的引用计数减少1,最后b的引用为1
在执行完del
操作之后,没有任何引用指向a
、b
对象,但是由于这两个对象各自包含一个对对方的引用,所以引用计数始终保持在1。
按照引用计数中内存回收的原理,由于a
和b
的计数不为0,所以在使用引用计数法进行内存管理的时候这两个对象不会被回收,它们会一直驻留在内存中,造成内存泄露。
标记清除机制主要用于解决循环引用问题。
标记清除算法是一种基于追踪回收(tracing GC)
技术实现的垃圾回收算法。主要分为两个阶段:
标记阶段,GC
对那些没有打上标记的非活动对象进行回收
对象之间通过引用即指针连接在一起,构成一个有向图,对象就是这个有向图的节点,而引用关系构成这个有向图的边。从根对象(root object)
出发,沿着有向边遍历对象,可达的对象会被标记为活动对象,不可达的对象就是要被清除的非活动对象。
根对象一般是全局变量、调用栈、寄存器等。
标记清除算法作为Python
辅助的垃圾收集技术,主要处理的是容器对象,因为对于字符串、数值对象等,不可能造成循环引用的问题,Python
会使用一个双向链表将这些容器对象组织起来。
对于标记清楚算法来说,有一个比较明显的缺点:为了清除非活动对象,需要扫描整个堆内存,哪怕只剩下小部分活动对象也需要扫描所有对象。
分代回收是一种以空间换时间的操作方式,建立在标记清除技术的基础之上,也是Python
辅助的垃圾收集技术,主要用于处理容器对象。
Python
会将内存根据对象的存活时间划分为不同的集合,每个集合称为一个代,主要会被分为3代:年轻代。中年代和老年代,它们会对应3个链表,对应的垃圾收集频率随着对象存活时间的增大而减小。
新创建的对象都会被分配在年轻代,当年轻代链表总数达到上限时,会触发Python
标签:def 就会 通过 解决 不同 占用 data 双向链表 有向图
原文地址:https://www.cnblogs.com/jeemzz/p/11420725.html