python中垃圾回收机制_Python垃圾回收机制简介

《Python垃圾回收机制简介》由会员分享,可在线阅读,更多相关《Python垃圾回收机制简介(6页珍藏版)》请在人人文库网上搜索。

1、众所周知,Py tho n是一门面向对象语言,在Python 的世界一切皆对象。所以一切变量的本质都是对象的一个指针而已。Python运行过程中会不停的创建各种变量,而这些变量是需要存储在内存中的,随着程 序的不断运行,变量数量越来越多,所占用的空间势必越来越大,如果对变量所占用的内存空间管理不当的话,那么肯定会出现out of memory 。程序大概率会被异常终止。因此,对于内存空间的有效合理管理变得尤为重要,那么Python 是怎么解决这个问题的呢。其实很简单,对不不可能再使用到的内存进行 回收即可,像 C语言中需要程序员手动释放内存就是这个道理。但问题 是如何确定哪些内存不再会被使用到。

2、呢?这就是我们今天要说的垃圾回 收了。目前垃圾回收比较通用的解决办法有三种,引用计数,标记清除以及分代回收。引用计数引用计数也是一种最直观,最简单的垃圾收集技术。在Python 中,大多数对象的生命周期都是通过对象的引用计数来管理的。其原理非常 简单,我们为每个对象维护一个ref 的字段用来记录对象被引用的次数,每当对象被创建或者被引用时将该对象的引用次数加一,当对象的 引用被销毁时该对象的引用次数减一,当对象的引用次数减到零时说明 程序中已经没有任何对象持有该对象的引用,换言之就是在以后的程序 运行中不会再次使用到该对象了,那么其所占用的空间也就可以被释放 了了。我们来看看下面的例子。imp。

3、ort osirriport psutil ff打印3程序占用的內存大小 def iprint_memory_info( naoe): pid = os.getpid()IP - psut il.Processpid)in-fo = p.rnern,ory_full_i nf oC )HB = 1024 * 1024memory = info. liss / MBprintC SSs usd 監d MB/ % (iname mmcry)#测试函數def f00():Iprint memory info( foo s ta rt) length - 1000 * 1009list - i for。

4、 i in range(length) prinit_inenory_info(foo end)foo)lprint_mGmopy_Lnf o( mair end) #输出结臬foo start used 6 MBfoo end used 55 MBmain end used 16 MB函数 prin t_memory_i nfo用来获取程序占用的内存空间大小,在foo 函数中创建一个包含一百万个整数的列表。从打印结果我们可以看出,创建完列表之后程序耗用的内存空间上升到了55 MB。而当函数foo调用完毕之后内存消耗又恢复正常。这是因为我们在函数foo中创建的list变量是局部变量,其作用域是。

5、当前函数内部,一旦函数执行完毕,局部变量的引用会被自动销毁,即其引用次数会变为零,所占用的内存空间也会被回收。为了验证我们的想法,我们对函数foo 稍加改造。代码如下:deff00():pr 1 nt memory_itif(foo start)length = 1000 * 1000list - i for i in 广ange(L&n莒th) print_inemory_irfo(foo end) return listfoo输出结果staPt used e MBfooend used EE MBfoo 函数调用结束其所消耗的内存也未被释 foo 内部产生的列表返回并在主程序中接收main。

6、 end used 55 MB稍加改造之后,即使放。主要是因为我们将函数之后,这样就会导致该列表的引用依然存在,该对象后续仍有可能被使 用到,垃圾回收便不会回收该对象。那么,什么时候对象的引用次数才会增加呢。下面四种情况都会导致对象引用次数加一。? 对象被创建(num=2)? 对象被引用(count=num )?对象作为参数传递到函数内部?对象作为一个元素添加到容器中同理,对象引用次数减一的情况也有四种。?对象的别名被显式销毁(del num)?对象的别名被赋予新的对象(num=30)?对象离开它的作用域(函数局部变量)?从容器中删除对象,或者容器被销毁引用计数看起来非常简单,实现起来也不复杂。

7、,只需要维护一个字 段保存对象被引用的次数即可,那么是不是就代表这种算法没有缺点了 呢。实则不然,我们知道引用次数为零的对象所占用的内存空间肯定是 需要被回收的。那引用次数不为零的对象呢,是不是就一定不能回收呢?我们来看看下面的例子,只是对函数foo进行了改造,其余未做更改。def f00 C):ipnint_in5mory_infofoe start) length = 105 * i0&0list_a = i for i in range(length) list_b = i for i in range(length lista. iappend(list_b)list_b. appen。

8、d(list_a,)print_inernory_inf foo)return list料#输出结果foo start used 6 MQfoo end used 9工 M6main end used 93 MB和 list_b ,foo 函我们看到,在函数 foo内部生成了两个列表list_alist_a然后将两个列表分别添加到另外一个中。由结果可以看出,即使 数结束之后其所占用的内存空间依然未被释放。这是因为对于 和list_b来说虽然没有被任何外部对象引用,但因为二者之间交叉引用,以至于每个对象的引用计数都不为零,这也就造成了其所占用的空 间永远不会被回收的尴尬局面。这个缺点是致命的。为。

9、了解决交叉引用 的问题,P ython弓I入了标记清除算法和分代回收算法。标记清除显然,可以包含其他对象引用的容器对象都有可能产生交叉引用问 题,而标记清除算法就是为了解决交叉引用的问题的。标记清除算法是一种基于对象可达性分析的回收算法,该算法分为两个步骤,分别是标 记和清除。标记阶段,将所有活动对象进行标记,清除阶段将所有未进行标记的对象进行回收即可。那么现在的问题变为了GC是如何判定哪些是活动对象的?事实上 GC会从根结点出发,与根结点直接相连或者间接相连的对 象我们将其标记为活动对象(该对象可达),之后进行回收阶段,将未标 记的对象(不可达对象) 进行清除。前面所说的根结点可以是全局变量。

10、, 也可以是调用栈。标记清除算法主要用来处理一些容器对象,虽说该方法完全可以做 到不误杀不遗漏,但 GC时必须扫描整个堆内存,即使只有少量的非可 达对象需要回收也需要扫描全部对象。这是一种巨大的性能浪费。分代回收由于标记清除算法需要扫描整个堆的所有对象导致其性能有所损耗, 而且当可以回收的对象越少时性能损耗越高。因此P ython引入了分代回收算法,将系统中存活时间不同的对象划分到不同的内存区域,共三 代,分别是0代,1代和2代。新生成的对象是 0代,经过一次垃 圾回收之后,还存活的对象将会升级到1代,以此类推,2代中的对象是存活最久的对象。那么什么时候触发进行垃圾回收算法呢。事实上随着程序的。

11、运行会1代。不断的创建新的对象,同时也会因为引用计数为零而销毁大部分对象, Pyth on会保持对这些对象的跟踪,由于交叉引用的存在,以及程序中使 用了长时间存活的对象,这就造成了新生成的对象的数量会大于被回收 的对象数量,一旦二者之间的差值达到某个阈值就会启动垃圾回收机制, 使用标记清除算法将死亡对象进行清除,同时将存活对象移动到 以此类推,当二者的差值再次达到阈值时又触发垃圾回收机制,将存活 对象移动到2代。这样通过对不同代的阈值做不同的设置,就可以做到 在不同代使用不同的时间间隔进行垃圾回收,以追求性能最大。事实上,所有的程序都有一个相似的现象,那就是大部分的对象生 存周期都是相当短的,。

12、 只有少量对象生命周期比较长,甚至会常驻内存,从程序开始运行持续到程序结束。而通过分代回收算法,做到了针对不 同的区域采取不同的回收频率,节约了大量的计算从而提高Py tho n的性能。除了上面所说的差值达到一定阈值会触发垃圾回收之外,我们还可以显示的调用 gc.collect()来触发垃圾回收,最后当程序退出时也会进行垃圾回收。总结本文介绍了 P ython的垃圾回收机制,垃圾回收是P ython自带的功能,并不需要程序员去手动管理内存。其中引用计数法是最简单直接 的,但是需要维护一个字段且针对交叉引用无能为力。标记清除算法主 要是为了解决引用计数的交叉引用问题,该算法的缺点就是需要扫描整 个堆的所有对象,有点浪费性能。而分代回收算法的引入则完美解决了 标记清除算法需要扫描整个堆对象的性能浪费问题。该算法也是建立在 标记清除基础之上的。最后我们可以通过gc.collectO手动触发GC的操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值