winston 发表于 2014-8-28 09:37:32

脚本语言python中关于垃圾回收的总结

这是个人对脚本语言python中关于垃圾回收的总结。最近在项目中使用Python处理数据,碰到内存泄漏的难题,折腾了好几天。处理过程中使用了多种测试工具定位问题,通过查看python gc的源代码、文档,得以理解的更多些。

python的gc并不是万能的。gc能消除简单的循环引用类型。普通的容器嵌套、循环引用并不会泄漏,因为所有被引用的容器,都会被加入回收列表,并不会因为容器被层层包裹而放过。不过在一些特定的情境下,仍然会产生泄漏问题,这些情况有待总结。在python中的垃圾回收,基本模式是引用计数。能够使用计数消除的对象,是不会交给gc操作的。gc只处理对象引用环的问题。因为循环引用是引用计数的致命伤,无法处理。


gc的.collect()功能:
如果开启 DEBUG_LEAK,实际上是不会真正回收对象的。因为这个复合标志,包含了DEBUG_SAVEALL,
gc.DEBUG_SAVEALLWhen set, all unreachable objects found will be appended to garbage rather than being freed. This can be useful for debugging a leaking program.

所以,使用这个标志看到不能回收的对象是不准确的。

collect()输出的unreachable数据,是被列为垃圾的对象,标明可以回收。输出的uncollectable数据,是包含__del__方法的对象,并不是真正意义上产生内存泄漏的对象。

内存泄漏的对象监测,是靠内存分析来完成的。简单的说就是在程序执行过后,本应被回收的对象仍然能够在内存中被检测到。如果循环产生这种对象,当然就会不断的吃内存,形成内存泄漏。最终以吃掉所有内存,程序挂掉告终。

解决的办法:
1、找到这种对象,重写相关代码,消除循环引用问题。有时候这比较困难,即便使用objgraph这种利器。
2、把执行过程封装为process,执行一遍就退出,让OS做全面的回收过程。这个可以作为临时的解决方案,不得已可以用。因为影响效率。

使用objgraph的方法:
http://mg.pov.lt/objgraph/objgraph.html
1、可以先使用 show_most_common_types 和show_growth 找出不应该存在的对象。
2、然后使用import pdb; pdb.set_trace()来设置调试断点。在中断后,使用objgraph.count('xxx') 来判断是否存在不能回收的对象。
3、尝试更改断点位置或者修改一下代码,判断是否能够回收了,对象消失。还可以使用show_backrefs来绘制图像,辅助判断。




页: [1]
查看完整版本: 脚本语言python中关于垃圾回收的总结