Python垃圾收集会那么慢吗?

Python垃圾收集会那么慢吗?,python,garbage-collection,root,performance,Python,Garbage Collection,Root,Performance,我的python应用程序有一个问题,我认为这与python垃圾收集有关,即使我不确定 问题是,我的应用程序退出并切换到一个函数到下一个函数需要很多时间 在我的应用中,我处理了非常大的字典,包含了从包裹的C++类中实例化的成千上万个大对象。 我在程序中输入了一些时间戳输出,在每个函数结束时,当函数中创建的对象超出范围时,解释器在调用下一个函数之前花费了大量时间。在应用程序结束时,当程序应该退出时,我观察到了同样的问题:从屏幕上的最后一个时间戳到出现新提示之间花费了大量时间(~h!) 内存使用是稳定

我的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()