Python内存管理:垃圾回收
http://blog.csdn.net/pipisorry/article/details/39647931
Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。也就是Python中的垃圾回收是以引用计数为主,分代收集为辅。
引用计数
概述
引用计数法在对象内部维护了一个被其它对象引用数的引用计数值。当这个引用计数值为0时。说明这个对象不再被其它对象引用,就能够被回收了。
结合源代码来看,全部Python对象的头部包括了这样一个结构PyObject(相当于继承自PyObject):
// object.h
struct _object {
Py_ssize_t ob_refcnt;
struct PyTypeObject *ob_type;
} PyObject;
ob_refcnt就是引用计数值。
比如,以下是int型对象的定义:
// intobject.h
typedef struct {
PyObject_HEAD
long ob_ival;
} PyIntObject;
引用计数的增减
导致引用计数+1的情况
对象被创建,比如a=23
对象被引用,比如b=a
对象被作为參数,传入到一个函数中,比如func(a)
对象作为一个元素。存储在容器中,比如list1=[a,a]
导致引用计数-1的情况
对象的别名被显式销毁。比如del a
对象的别名被赋予新的对象,比如a=24
一个对象离开它的作用域,比如f函数运行完成时,func函数中的局部变量(全局变量不会)
对象所在的容器被销毁。或从容器中删除对象
引用计数演示样例
def func(c):
print 'in func function', sys.getrefcount(c) - 1
print 'init', sys.getrefcount(11) - 1
a = 11
print 'after a=11', sys.getrefcount(11) - 1
b = a
print 'after b=1', sys.getrefcount(11) - 1
func(11)
print 'after func(a)', sys.getrefcount(11) - 1
list1 = [a, 12, 14]
print 'after list1=[a,12,14]', sys.getrefcount(11) - 1
a=12
print 'after a=12', sys.getrefcount(11) - 1
del a
print 'after del a', sys.getrefcount(11) - 1
del b
print 'after del b', sys.getrefcount(11) - 1
# list1.pop(0)
# print 'after pop list1',sys.getrefcount(11)-1
del list1
print 'after del list1', sys.getrefcount(11) - 1
init 24
after a=11 25
after b=1 26
in func function 28
after func(a) 26
after list1=[a,12,14] 27
after a=12 26
after del a 26
after del b 25
after del list1 24
查看一个对象的引用计数:sys.getrefcount(a)能够查看a对象的引用计数。可是比正常计数大1,因为调用函数getrefcount的时候传入a。这也会让a的引用计数+1。
循环引用导致内存泄露
def f2():
while True:
c1=ClassA()
c2=ClassA()
c1.t=c2
c2.t=c1
del c1
del c2
运行f2()。进程占用的内存会不断增大。
创建了c1,c2后,0x237cf30(c1相应的内存,记为内存1),0x237cf58(c2相应的内存,记为内存2)这两块内存的引用计数都是1,运行c1.t=c2和c2.t=c1后,这两块内存的引用计数变成2。在del c1后。内存1的对象的引用计数变为1。因为不是为0,所以内存1的对象不会被销毁,所以内存2的对象的引用数依旧是2,在del c2后,同理,内存1的对象,内存2的对象的引用数都是1。
尽管它们两个的对象都是能够被销毁的。可是因为循环引用,导致垃圾回收器都不会回收它们,所以就会导致内存泄露。
引用计数法优缺点
引用计数法有非常明显的长处
高效
运行期没有停顿
对象有确定的生命周期
易于实现
原始的引用计数法也有明显的缺点:
维护引用计数的次数和引用赋值成正比,而不像mark and sweep等基本与回收的内存数量有关。
无法解决循环引用的问题。A和B相互引用而再没有外部引用A与B中的不论什么一个,它们的引用计数都为1,但显然应该被回收。
为了解决这两个致命弱点,Python又引入了以下两种GC机制。
标记-清除
“标记-清除”法是为了解决循环引用问题。能够包括其它对象引用的容器对象(如list, dict, set,甚至class)都可能产生循环引用,为此,在申请内存时,全部容器对象的头部又加上了PyGC_Head来实现“标记-清除”机制。
// objimpl.h
typedef union _gc_head {
struct {
union _gc_head *gc_next;
union _gc_head *gc_prev;
Py_ssize_t gc_refs;
} gc;
long double dummy; /* force worst-case alignment */
} PyGC_Head;
垃圾标记时,先将集合中对象的引用计数复制一份副本(以免在操作过程中破坏真实的引用计数值)。然后操作这个副本,遍历对象集合,将被引用对象的引用计数副本值减1。
然后依据引用计数副本值是否为0将集合内的对象分成两类。reachable和unreachable,当中unreachable是能够被回收的对象。在处理了weak reference和finalizer等琐碎细节后(本文不展开讲述,有兴趣的请參考python源代码),就能够回收unreachable中的对象了。
分代回收
分代回收的总体思想是:将系统中的全部内存块依据其存活时间划分为不同的集合。每一个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。
用来表示“代”的结构体是gc_generation。 包括了当前代链表表头、对象数量上限、当前对象数量:
// gcmodule.c
struct gc_generation {
PyGC_Head head;
int threshold; /* collection threshold */
int count; /* count of allocations or collections of younger
generations */
};
Python默认定义了三代对象集合。索引数越大。对象存活时间越长。
新生成的对象会被增加第0代,前面_PyObject_GC_Malloc中省略的部分就是Python GC触发的时机。每新生成一个对象都会检查第0代有没有满。假设满了就開始着手进行垃圾回收。
gc模块经常使用功能解析
Garbage Collector interface
gc模块提供一个接口给开发人员设置垃圾回收的选项。
上面说到,採用引用计数的方法管理内存的一个缺陷是循环引用。而gc模块的一个主要功能就是解决循环引用的问题。
应用
项目中避免循环引用
引入gc模块。启动gc模块的自己主动清理循环引用的对象机制
因为分代收集,所以把须要长期使用的变量集中管理。并尽快移到二代以后,降低GC检查时的消耗
gc模块唯一处理不了的是循环引用的类都有__del__方法,所以项目中要避免定义__del__方法,假设一定要使用该方法,同一时候导致了循环引用。须要代码显式调用gc.garbage里面的对象的__del__来打破僵局
from:http://blog.csdn.net/pipisorry/article/details/39647931
ref: [python的内存管理机制]
[《Python源代码剖析》,陈儒著,2008]
[Python垃圾回收机制]*
Python内存管理:垃圾回收的更多相关文章
- python内存管理&垃圾回收
python内存管理&垃圾回收 引用计数器 环装双向列表refchain 在python程序中创建的任何对象都会放在refchain连表中 name = '张三' age = 18 hobby ...
- [Python之路] 内存管理&垃圾回收
一.python源码 1.准备源码 下载Python源码:https://www.python.org/ftp/python/3.8.0/Python-3.8.0.tgz 解压得到文件夹: 我们主要关 ...
- Java 类加载机制 ClassLoader Class.forName 内存管理 垃圾回收GC
[转载] :http://my.oschina.net/rouchongzi/blog/171046 Java之类加载机制 类加载是Java程序运行的第一步,研究类的加载有助于了解JVM执行过程,并指 ...
- 内存管理 垃圾回收 C语言内存分配 垃圾回收3大算法 引用计数3个缺点
小结: 1.垃圾回收的本质:找到并回收不再被使用的内存空间: 2.标记清除方式和复制收集方式的对比: 3.复制收集方式的局部性优点: https://en.wikipedia.org/wiki/C_( ...
- [CLR via C#]21. 自动内存管理(垃圾回收机制)
目录 理解垃圾回收平台的基本工作原理 垃圾回收算法 垃圾回收与调试 使用终结操作来释放本地资源 对托管资源使用终结操作 是什么导致Finalize方法被调用 终结操作揭秘 Dispose模式:强制对象 ...
- 【python测试开发栈】—python内存管理机制(二)—垃圾回收
在上一篇文章中(python 内存管理机制-引用计数)中,我们介绍了python内存管理机制中的引用计数,python正是通过它来有效的管理内存.今天来介绍python的垃圾回收,其主要策略是引用计数 ...
- python内存管理及垃圾回收
一.python的内存管理 python内部将所有类型分成两种,一种由单个元素组成,一种由多个元素组成.利用不同结构体进行区分 /* Nothing is actually declared to b ...
- Python 内存管理与垃圾回收
Python 内存管理与垃圾回收 参考文献:https://pythonav.com/wiki/detail/6/88/ 引用计数器为主标记清除和分代回收为辅 + 缓存机制 1.1 大管家refcha ...
- 转发:[Python]内存管理
本文为转发,原地址为:http://chenrudan.github.io/blog/2016/04/23/pythonmemorycontrol.html 本文主要为了解释清楚python的内存管理 ...
随机推荐
- HashCode()的作用
在实现Hash算法的集合里面,例如HashSet,该集合不能存放相同的数据,HashSet会根据对象的equals()和hashCode()方法来判断要存放的数据是否已经存在.Hash算法把HashS ...
- 【强联通分量缩点】【最长路】【spfa】CH Round #59 - OrzCC杯NOIP模拟赛day1 队爷的讲学计划
10分算法:对于城市网络为一条单向链的数据, 20分算法:对于n<=20的数据,暴力搜出所有的可能路径. 结合以上可以得到30分. 60分算法:分析题意可得使者会带着去的城市也就是这个城市所在强 ...
- iOS开发 Swift开发数独游戏(五)显示游戏答案
要点是设置好Tag就好,通过代码找到并初始化即可. 1: // 2: // ShowAnswerController.swift 3: // sudoku-v02 4: // 5: // ...
- EditText中禁止输入中文的方法
应用场景 在Android应用中有时需要EditText中只允许输入约定的一些字符,禁止输入其他字符.这里列举了一些可能的应用场景. 1. 场景一 在通讯录保存好友信息界面中填写好友的电话号码时,应当 ...
- 使用UNetbootin工具制作的CentOS 6.9镜像U盘在启动安装过程中出现:unable to read package metadata.this may be due to a missing repodata directory
1.制作: 2.重命名文件 (前) (后) 这些文件是拷贝另一个得来的,并且后面的命名是根据repomd.xm这个文件来的. 参考: http://blog.csdn.net/maijunjin/ar ...
- 网络采集软件核心技术剖析系列(2)---如何使用C#语言获得任意站点博文的正文及标题
一 本系列随笔概览及产生的背景 本系列开篇受到大家的热烈欢迎,这对博主是莫大的鼓励,此为本系列第二篇,希望大家继续支持,为我继续写作提供动力. 自己开发的豆约翰博客备份专家软件工具问世3年多以来,深受 ...
- 使用apt-mirror建立局域网内的Debian/Ubuntu源镜像
转:http://forum.ubuntu.org.cn/viewtopic.php?t=41791 第一次翻译,翻译得不好还请大家见谅,多多指出错误~!:) 原文可以见如下的贴子:http://fo ...
- ASP.NET Core 1.0基础之日志
过年出去玩了一圈,回来继续翻译.前两天偷懒没有翻译,只是转了两篇C# 7计划中的新features,大家还是很支持的.现在继续完善这个系列. 来源https://docs.asp.net/en/lat ...
- VSM(Virtual Storage Manager For Ceph)安装教程
转载注明出处,陈小跑 http://www.cnblogs.com/chenxianpao/p/5770271.html 一.安装环境 OS:CentOS7.2 VSM:v2.1 released 二 ...
- cdev结构体及其相关函数
一.在Linux2.6内核中一个字符设备用cdev结构来描述,其定义如下: struct cdev { struct kobject kobj; struct module *owner; //所属模 ...