丨带你解析python垃圾回收机制_第1页
丨带你解析python垃圾回收机制_第2页
丨带你解析python垃圾回收机制_第3页
丨带你解析python垃圾回收机制_第4页
丨带你解析python垃圾回收机制_第5页
已阅读5页,还剩33页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

器。在工程学的演化中,逐渐出现了寄存器、易失性 回到Python应用层我们知道,Python程序在运行的时候,需要在内存中开辟存空间管理不善就很容易OOM(outofmemory),则显得更为重要,不然很容易内存泄漏。什么是内存泄这里的泄漏,并不是说你的内存出现了问题,被内存泄漏也不是指你的内存在物理上了,而是意味着那么,Python又是怎么解决这些问题的?换句话说,对于不再用到的内存空间,Python是通过什么机制来回收这我们反复提过好几次Python一切皆对象。因此,你所看到的切变量,本质上都是对象的个指针。那么,怎么知道一个对象,是否都不能被调用了呢个对象的计数(指针数)为0的时候,说明这个对象永我们来看一个例代importimport3#显示当前python程序占用的内存defpid=p=8info= info.uss/1024./print('{}memoryused:{}MB'.format(hint,代defa=[iforiin show_memory_info('aftera589输出initialmemoryused: afteracreatedmemoryused: finishedmemoryused:48.109375通过这个示例,你可以看到,调用函数func(),在列表a被创建之后,内存占用迅速增加到了433MB:而在函数调用这是因为,函数内部的列表a是局部变量,在函数返回后,局部变量的会注销掉;此时,列表a所指代对象数为0,Python便会执行回收,因此之前占用的明白了这个原理后,我们稍微修改一下代代123global4a=[iforiinshow_memory_info('aftera6910##########输出initialmemoryused: afteracreatedmemoryused: finishedmemoryused: 新的这段代码中,globala表示将a为全局变量。那么,即使函数返回后,列表的依然存在,于是对象就不那么依然存在,回收就不会被触发,大量内存仍然被占用代defa=[iforiin show_memory_info('afterareturn6a=910##########输出initialmemoryused: afteracreatedmemoryused:434.515625finishedmemoryused:434.515625这是最常见的几种情况。由表及里,下面,我们深入看Python内部的计数机制。老规矩,先来看代码代import23a=4#两次,一次来自a,一次来自7def#四次,a,python的函数调用栈,函数参数,和1214#两次,一次来自a,一次来自getrefcount,函数func1517##########输出简单介绍一下,sys.getrefcount函数,可以查看一个变量的次数。这段代码本身应该很好理解,不过别忘了,getrefcount本身也会引入一次计数两次,一次来自函数栈,另一个是函数参数。代1import23a=45print(sys.getrefcount(a))#67b=89print(sys.getrefcount(a))#c=d=e=f=g=17print(sys.getrefcount(a))#19##########输出212223看到这段代码,需要你稍微注意下,abcdeg这些变量全部指代的是同一个对象,而sys.getrefcount()函数并不是统计一个指针,统计一个对象被的次数,所以最后一共会有八次。理解这个概念后,释放是一种非常自然和清晰的思想。相比C语言里,你需要使用 Python的回收在这里可以说是省力了。方法同样很简单。你只需要先调用dela删除一个对象;然后强制调用gc.collect(),即可手动启动回收。代1import2345a=[iforiin 67show_memory_info('aftera8del15输出initialmemoryused: afteracreatedmemoryused: finishmemoryused: Traceback<ipython-input-12-153e15063d8a>in 12--->1328NameError:name'a'isnot到这里,是不是觉得回收非常简单呀问:次数为0是回收启动的充要条件吗?还有没有这个问题,你能回答的上来吗么一个问题:如果有两个对象,它们互相,并且不再被请仔细观察下面这段代码代defa=[iforiin b=[iforiin show_memory_info('aftera,b812输出initialmemoryused:47.984375aftera,bcreatedmemoryused: finishedmemoryused: 这里,a和b互相,并且,作为局部变量,在函数func调用结束后,a和b这两个指针从程序意义上已经不互相,导致它们的数都不为0。试想一下,如果这段代码出现在生产环境中,哪怕a和bPython所占用的内存一定会变得越来越大,最终服务题不大。可是,更隐蔽的情况是出现一个环,在工程码比较复杂的情况下,环还真不一定能被轻易发现那么,我们应该怎么做呢事实上,Python身能够处理这种情况,我们刚刚讲过的,可以显式调用gc.collect(),来启动回收。代import2defa=[iforiin b=[iforiin show_memory_info('aftera,b15##########输出17initialmemoryused: 18aftera,bcreatedmemoryused: 19finishedmemoryused: 所以你看,Python的回收机制并没有那么弱Python使用标记清除(mark-sweep)算法和分代收在是没有任何意义的,自然的,我们就需要对它们进行当然,每次都遍历全图,对于Python而言是一种巨大的性能浪费。所以,在Python的回收实现中,mark-sweep使用双向链表了一个数据结构,并且只考虑容器类的对象(只有容器类对象才有可能产生循环)。具体算法这里我就不再多讲了,毕竟我们的重点是关注应而分代收集算法,则是另一个优化Python将所有对象分为三代。刚刚创立的对象是第0代;经过一次回收后,依然存在的对象,便会依次从上一代单独指定的。当回收器中新增对象减去删除对象达到相Python的性能。吧!没错,计数是其中最简单的实现,不过切记,的可能性,我们所讲的循环正是其中一种。它就是objgraph,一个非常好用的可视化关系的包在这个包中,我主要推荐两个函数,第一个是show_refs(),它可以生成清晰的关系图。现,有两个list互相,说明这里极有可能引起内存泄代1import23a=[1,2,4b=[4,5,56789而另一个非常有用的函数show_backrefs()。下面同样代1import23a=[1,2,4b=[4,5,56789我仍旧推荐你掌握它,因为这个API有很多有用的参数,比出格式控制(filenameoutput)、节点过滤(filter,最后,带你来总结一下。今天这节课,我们深入了解Python的回收机制,我主要强调下面这几点回收是Python自带的机制,用于自动释放不会再用计数是其中最简单的实现,不过切记,这只是充分非必要条件,因为循环需要通过不可达判定,来确定是Python的自动回收算法包括标记清除和分代收集,主要调试内存泄漏方面,objgraph是很好的可视化分析工最后给你留一道思考题。你能否自己实现一个回收判定算法呢?我的要求很简单,输入是个有向图,给定起点, 售卖。页面已增加防盗追踪,上一 23|你真的懂PythonGIL(全局解释器锁)吗下一 25|答疑 GIL与多线程是什么关系呢言精选留言言Jingxiaodfs(深度记号。遍历完成后,再对所有节点扫一遍,没有被做记展2Graphviewer(xdot)andimagerenderer(dot)notfound,not nganythingelse展3 2陈迪循环情况下Python不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论