我的 python 应用程序有问题,我认为它与 python 垃圾收集有关,即使我不确定......
问题是我的应用程序需要很长时间才能退出并从一个功能切换到下一个功能。
在我的应用程序中,我处理非常大的字典,其中包含从包装的 C++ 类实例化的数千个大对象。
我在我的程序中放了一些时间戳输出,我看到在每个函数结束时,当函数内部创建的对象超出范围时,解释器在调用下一个函数之前会花费大量时间。我在应用程序结束时观察到同样的问题,当程序应该退出时:在屏幕上的最后一个时间戳和新提示的出现之间花费了很多时间(〜小时!)。
内存使用稳定,所以我真的没有内存泄漏。
有什么建议吗?
可能是数以千计的大型 C++ 对象的垃圾收集速度很慢?
有没有加快速度的方法?
更新:
非常感谢您的所有回答,您给了我很多调试代码的提示:-)
我在 Scientific Linux 5 上使用 Python 2.6.5,这是一个基于 Red Hat Enterprise 5 的定制发行版。
实际上,我并没有使用 SWIG 为我们的 C++ 代码获取 Python 绑定,而是使用 Reflex/PyROOT 框架。我知道,它在粒子物理学之外不是很为人所知(但仍然是开源的并且免费提供),我必须使用它,因为它是我们主框架的默认设置。
在这种情况下,Python 端的 DEL 命令不起作用,我已经尝试过了。 DEL只删除了链接到C++对象的python变量,而不是内存中的对象本身,仍然归C++端所有……
...我知道,我猜这不是标准的,而且有点复杂,抱歉:-P
但是按照您的提示,我将分析我的代码,并按照您的建议向您提供更多详细信息。
附加更新:
好的,按照你的建议,我用cProfile 检测了我的代码,我发现实际上gc.collect() 函数是占用大部分运行时间的函数!!
这里是cProfile + pstats print_stats() 的输出:
>>> p.sort_stats("时间").print_stats(20)
2010 年 10 月 20 日星期三 17:46:02 mainProgram.profile
在 548.060 CPU 秒内进行 547303 次函数调用(542629 次原语调用)
排序:内部时间
由于限制,名单从 727 减少到 20
ncalls tottime percall cumtime percall filename:lineno(function)
4 345.701 86.425 345.704 86.426 {gc.collect}
1 167.115 167.115 200.946 200.946 PlotD3PD_v3.2.py:2041(PlotSamplesBranches)
28 12.817 0.458 13.345 0.477 PlotROOTUtils.py:205(保存项目)
9900 10.425 0.001 10.426 0.001 PlotD3PD_v3.2.py:1973(组织风格)
6622 5.188 0.001 5.278 0.001 PlotROOTUtils.py:403(__init__)
57 0.625 0.011 0.625 0.011 {内置方法加载}
103 0.625 0.006 0.792 0.008 dbutils.py:41(死锁包裹)
14 0.475 0.034 0.475 0.034 {“cPickle.Pickler”对象的“转储”方法}
6622 0.453 0.000 5.908 0.001 PlotROOTUtils.py:421(CreateCanvas)
26455 0.434 0.000 0.508 0.000 /opt/root/lib/ROOT.py:215(__getattr__)
[...]
>>> p.sort_stats("累积").print_stats(20)
2010 年 10 月 20 日星期三 17:46:02 mainProgram.profile
在 548.060 CPU 秒内进行 547303 次函数调用(542629 次原语调用)
排序:累计时间
由于限制,名单从 727 减少到 20
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.001 0.001 548.068 548.068 PlotD3PD_v3.2.py:2492(主)
4 0.000 0.000 346.756 86.689 /usr/lib//lib/python2.5/site-packages/guppy/heapy/Use.py:171(堆)
4 0.005 0.001 346.752 86.688 /usr/lib//lib/python2.5/site-packages/guppy/heapy/View.py:344(堆)
1 0.002 0.002 346.147 346.147 PlotD3PD_v3.2.py:2537(LogAndFinalize)
4 345.701 86.425 345.704 86.426 {gc.collect}
1 167.115 167.115 200.946 200.946 PlotD3PD_v3.2.py:2041(PlotBranches)
28 12.817 0.458 13.345 0.477 PlotROOTUtils.py:205(保存项目)
9900 10.425 0.001 10.426 0.001 PlotD3PD_v3.2.py:1973(组织风格)
13202 0.336 0.000 6.818 0.001 PlotROOTUtils.py:431(PlottingCanvases)
6622 0.453 0.000 5.908 0.001 /root/svn_co/rbianchi/SoftwareDevelopment
[...]
>>>
因此,在两个输出中,分别按“时间”和“累积”时间排序,gc.collect() 是占用我程序运行时间最多的函数! :-P
这是内存分析器Heapy 的输出,就在返回main() 程序之前。
返回前的内存使用情况:
一组 65901 个对象的分区。总大小 = 4765572 字节。
索引计数 % 大小 % 累积 % 种类(类/类字典)
0 25437 39 1452444 30 1452444 30 力量
1 6622 10 900592 19 2353036 49 PlotROOTUtils.Canvas 的字典
2 109 0 567016 12 2920052 61 模块字典
3 7312 11 280644 6 3200696 67 元组
4 6622 10 238392 5 3439088 72 0xa4ab74c
5 6622 10 185416 4 3624504 76 PlotROOTUtils.Canvas
6 2024 3 137632 3 3762136 79 种代码类型
7 263 0 129080 3 3891216 82 dict(无所有者)
8 254 0 119024 2 4010240 84 字典类型
9 254 0 109728 2 4119968 86型
索引计数 % 大小 % 累积 % 种类(类/类字典)
10 1917 3 107352 2 4264012 88 功能
11 3647 5 102116 2 4366128 90 ROOT.MethodProxy
12 148 0 80800 2 4446928 92 类字典
13 1109 2 39924 1 4486852 93 __builtin__.wrapper_descriptor
14 239 0 23136 0 4509988 93 名单
15 87 0 22968 0 4532956 94 guppy.etc.Glue.Interface 的字典
16 644 1 20608 0 4553564 94 种类型。BuiltinFunctionType
17 495 1 19800 0 4573364 94 __builtin__.weakref
18 23 0 11960 0 4585324 95 guppy.etc.Glue.Share 的字典
19 367 1 11744 0 4597068 95 __builtin__.method_descriptor
知道为什么或如何优化垃圾收集吗?
我可以做更详细的检查吗?