Python垃圾收集会那么慢吗?
我的python应用程序有一个问题,我认为这与python垃圾收集有关,即使我不确定 问题是,我的应用程序退出并切换到一个函数到下一个函数需要很多时间 在我的应用中,我处理了非常大的字典,包含了从包裹的C++类中实例化的成千上万个大对象。 我在程序中输入了一些时间戳输出,在每个函数结束时,当函数中创建的对象超出范围时,解释器在调用下一个函数之前花费了大量时间。在应用程序结束时,当程序应该退出时,我观察到了同样的问题:从屏幕上的最后一个时间戳到出现新提示之间花费了大量时间(~h!) 内存使用是稳定的,所以我没有真正的内存泄漏 有什么建议吗Python垃圾收集会那么慢吗?,python,garbage-collection,root,performance,Python,Garbage Collection,Root,Performance,我的python应用程序有一个问题,我认为这与python垃圾收集有关,即使我不确定 问题是,我的应用程序退出并切换到一个函数到下一个函数需要很多时间 在我的应用中,我处理了非常大的字典,包含了从包裹的C++类中实例化的成千上万个大对象。 我在程序中输入了一些时间戳输出,在每个函数结束时,当函数中创建的对象超出范围时,解释器在调用下一个函数之前花费了大量时间。在应用程序结束时,当程序应该退出时,我观察到了同样的问题:从屏幕上的最后一个时间戳到出现新提示之间花费了大量时间(~h!) 内存使用是稳定
可以是成千上万个大型C++对象的垃圾收集,它们慢了-< /p> 有没有办法加快这一进程
更新: 非常感谢您的回答,您给了我很多调试代码的提示:-) 我在Scientific Linux 5上使用Python 2.6.5,这是一个基于Red Hat Enterprise 5的定制发行版。 实际上,我不使用SWIG来为我们的C++代码获得Python绑定,而是使用反射/ pyRoST框架。我知道,它在粒子物理之外并不广为人知(但仍然是开源的,免费提供),我不得不使用它,因为它是我们的主框架的默认设置 在这种情况下,Python端的DEL命令不起作用,我已经尝试过了。DEL只删除与C++对象链接的Python变量,而不是内存中的对象本身,它仍然由C++侧……/P> …我知道,我想这不是标准的,而且有点复杂,对不起:-p 但按照您的提示,我将分析我的代码,并按照您的建议,向您提供更多详细信息 其他更新: 好的,按照你的建议,我用cProfile
插入了我的代码,我发现实际上gc.collect()
函数占用了大部分运行时间
这里是cProfile
+pstats
print_stats()的输出:
你知道为什么或者如何优化垃圾收集吗
有没有更详细的检查我可以做?
< P>是的,它可以是垃圾回收,但它也可以与C++代码同步,或者完全不同的东西(很难不用代码)。无论如何,您应该看看如何发现问题以及如何加快速度。如果您的问题确实是垃圾收集,请在使用
del()完成对象时尝试显式释放它们
一般来说,这听起来不像是垃圾收集问题,除非我们讨论的是TB级内存
我同意S.Lott。。。分析你的应用程序,然后带回代码片段和结果,我们会更有帮助。当分配了许多对象而没有取消分配任何对象时,会导致垃圾收集的二次时间,即大列表的填充。
有两个简单的解决方案:
在填充大型列表之前禁用垃圾收集,然后启用它
或更新到
我更喜欢第二种解决方案,但它并不总是一种选择;) “有什么建议吗?”。使用探查器获取更多有关时间花费在何处的事实。将结果作为问题的更新发布。@否:实际上,Python使用refcounting,因此将收集未引用的对象。与优秀JVM和.NET中的聪明野兽相比,Python的GC相当简单。@delnan准确地说,CPython的实现具有这种行为。我似乎记得有些实验版本的算法更为奇特。@Paul:True,IronPython和Jython使用各自VM的GC(因此没有refcouting)。但通常,这一点可以忽略;)哪个操作系统和哪个版本?所以您的内存使用是稳定的——稳定地大于进程可用的实际内存?你有多少物理内存?在流程开始前,有多少是免费的?就在它离开之前?你试过用正常数量的1/4、1/2、3/4的对象运行它吗?你观察到了什么?它是逐渐变得迟钝,还是突然“撞到墙上”?考虑告诉我们有多少对象/分钟/小时,而不是“很多”和“数千”等等。代码> DEL>代码>并没有释放任何东西。它只是从当前范围中删除一个变量,即删除一个引用。但是Python是refcounted的(一个更复杂的GC确实存在并运行,但只在循环引用上运行)——如果一堆对象在函数结束时得到GC,或者在您认为完成时在小块中得到GC,这其实并不重要。一般来说,是的。在病理情况下,释放小块可能会有所帮助。习惯性地到处使用del
往往表明您不是在用Python编程。谢谢,Paul和Delnan。实际上,我也尝试使用del(),但在这种情况下不起作用。正如我在我的问题的更新中所说的,我使用一个叫做root()的开源框架,它有自己的Python绑定系统(称为反射),即使删除()删除所有C++对象的Python引用,对象本身也会留在内存中…但即使现在我也找到了一种明确删除它们的方法,gc.collect函数似乎占用了大部分运行时间。。。有进一步检查的建议吗?再次感谢您的帮助Hi Kris,显然它有垃圾收集器问题。我用cProfile的输出更新了我的问题,似乎gc.collect占用了大部分运行时间。。。我将按照您的建议看一看SIG-Python/C++,看看它在某些上下文中是否是一个已知的问题
>>> p.sort_stats("time").print_stats(20)
Wed Oct 20 17:46:02 2010 mainProgram.profile
547303 function calls (542629 primitive calls) in 548.060 CPU seconds
Ordered by: internal time
List reduced from 727 to 20 due to restriction
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(SaveItems)
9900 10.425 0.001 10.426 0.001 PlotD3PD_v3.2.py:1973(HistoStyle)
6622 5.188 0.001 5.278 0.001 PlotROOTUtils.py:403(__init__)
57 0.625 0.011 0.625 0.011 {built-in method load}
103 0.625 0.006 0.792 0.008 dbutils.py:41(DeadlockWrap)
14 0.475 0.034 0.475 0.034 {method 'dump' of 'cPickle.Pickler' objects}
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("cumulative").print_stats(20)
Wed Oct 20 17:46:02 2010 mainProgram.profile
547303 function calls (542629 primitive calls) in 548.060 CPU seconds
Ordered by: cumulative time
List reduced from 727 to 20 due to restriction
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.001 0.001 548.068 548.068 PlotD3PD_v3.2.py:2492(main)
4 0.000 0.000 346.756 86.689 /usr/lib//lib/python2.5/site-packages/guppy/heapy/Use.py:171(heap)
4 0.005 0.001 346.752 86.688 /usr/lib//lib/python2.5/site-packages/guppy/heapy/View.py:344(heap)
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(SaveItems)
9900 10.425 0.001 10.426 0.001 PlotD3PD_v3.2.py:1973(HistoStyle)
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
[...]
>>>
memory usage before return:
Partition of a set of 65901 objects. Total size = 4765572 bytes.
Index Count % Size % Cumulative % Kind (class / dict of class)
0 25437 39 1452444 30 1452444 30 str
1 6622 10 900592 19 2353036 49 dict of PlotROOTUtils.Canvas
2 109 0 567016 12 2920052 61 dict of module
3 7312 11 280644 6 3200696 67 tuple
4 6622 10 238392 5 3439088 72 0xa4ab74c
5 6622 10 185416 4 3624504 76 PlotROOTUtils.Canvas
6 2024 3 137632 3 3762136 79 types.CodeType
7 263 0 129080 3 3891216 82 dict (no owner)
8 254 0 119024 2 4010240 84 dict of type
9 254 0 109728 2 4119968 86 type
Index Count % Size % Cumulative % Kind (class / dict of class)
10 1917 3 107352 2 4264012 88 function
11 3647 5 102116 2 4366128 90 ROOT.MethodProxy
12 148 0 80800 2 4446928 92 dict of class
13 1109 2 39924 1 4486852 93 __builtin__.wrapper_descriptor
14 239 0 23136 0 4509988 93 list
15 87 0 22968 0 4532956 94 dict of guppy.etc.Glue.Interface
16 644 1 20608 0 4553564 94 types.BuiltinFunctionType
17 495 1 19800 0 4573364 94 __builtin__.weakref
18 23 0 11960 0 4585324 95 dict of guppy.etc.Glue.Share
19 367 1 11744 0 4597068 95 __builtin__.method_descriptor
l = []
gc.disable()
for x in xrange(10**6):
l.append(x)
gc.enable()