当前位置:  首页>> 技术小册>> Python高性能编程与实战

对于CPython解释器或虚拟机来说,最常用也是最简单的垃圾回收优化手段就是降低垃圾回收的频率。Python中降低垃圾回收频率的手段一般有两种:第一种是引入Python中的gc包,另一种是结合Python中的垃圾回收算法。

gc包是CPython官方为Python开发者提供的一个资源包。该包中包含对Python中的垃圾进行回收的基础操作方法。开发者可以结合这些基础操作方法,手动设置Python垃圾回收的时机。Python中垃圾回收的基础操作方法共有4个,分别是disable()、collect()、set_threshold ()、set_debug ()。这四种基础操作方法分别用于暂停自动垃圾回收、返回垃圾回收机制所找到无法到达的对象的数量、设置Python垃圾回收的阈值、设置垃圾回收的调试标记并将调试信息写入std.err()方法。对于上述基础操作方法的使用,笔者写了几个示例代码,具体如下:

我们知道,Python中常用的垃圾回收算法是引用计数算法。引用计数算法是一种非常高效的内存管理手段,当Python对象被调用时,其引用计数器的值就增加1;当Python对象不再被调用时,其引用计数器的值就会减1,直到减到0为止。当Python中一个对象的引用计数器的值等于0时,该对象就会被删除。

上述代码的执行结果如图13-5所示。

gc.disable()方法用于暂停自动垃圾回收。当自动的垃圾回收机制暂停时,Python对象的引用计数器值也就不再由CPython解释器或虚拟机进行自动管理,而是交由开发者手动进行干预。在上述代码中,笔者使用了objgraph第三方工具包来查看a、b两个对象引用计数器的值。通过打印结果可以发现,这两个对象的引用计数器的值均为0,那么当不再调用gc.disable()方法时,a、b两个对象就会被回收,以此来实现降低垃圾回收的频率。

开发者需要对gc.disable()方法进行灵活应用,在确实需要暂停自动垃圾回收的地方大胆使用,在那些确实不需要暂停自动垃圾回收的地方就一定不能使用,切记不能为了Python代码的执行速度而随意滥用该方法。

当开发者在编写Python代码时,切记不要编写重复引用或循环引用的Python代码,如果在不经意间编写了循环引用的代码,那么在进行代码审查时,一定要对其进行优化,因为这种代码不会被Python中的垃圾回收机制回收。笔者编写了一个简单的循环引用代码:

在调用上述代码中的test3()方法时就会发生对象a和对象b循环引用的情况,导致垃圾回收机制一直不能对上述代码进行回收,因为上述代码执行完毕时,对象a和对象b的引用计数器的值均为1,如图13-6所示。

如果开发者不将该循环引用进行优化,上述代码所占用的内存空间将会越来越大。结束上述代码的循环引用其实很简单,只需要在test3()方法中调用相对应的destroy()方法即可,代码如下所示:

在test3()方法中,笔者分别调用了对象a和对象b的destroy()方法,来手动结束这一循环引用。在调用了对象a和对象b的destroy()方法之后,对象a和对象b的引用计数器的值变为0,如图13-7所示。

这样,Python中的垃圾回收机制就可以回收掉上述代码了(详见上述回收过程)。位于test3()方法中的destroy()方法只是笔者用于演示手动终止循环引用的标记方法,并不代表Python中所有的循环引用都需要通过这种方法进行终止,而是应该根据实际的项目环境和代码环境,来编写具体Python项目的循环引用终止条件,这样才能降低垃圾回收的频率。

当我们通过上述手段降低了垃圾回收频率之后,Python项目在运行时就不会有明显的卡顿,对于CPython的内存占用来说,虽说占用了一些内存空间,但是项目整体的运行效率会得到提升。这是一种以空间换取时间的优化方式。


该分类下的相关小册推荐: