如何在pygame.surfarray.pixels2d中防止内存泄漏?

时间:2015-10-24 23:05:24

标签: python performance memory-leaks pygame surface

我有一个生成器,使用Surface将一系列简单的翻译效果应用于图像pygame.surfarray.pixels2d()。然而,我很快发现,随着循环循环,Python的内存使用膨胀,最终抛出MemoryError并崩溃。

在试图找出原因时,我到达了这个简单的循环:

import pygame
testsurf = pygame.Surface((1,1))
while True:  # normally, this would be a generator.
    testarray = pygame.surfarray.pixels2d(testsurf)
    del testarray   # only necessary if the Surface is blitted.

此代码是否在实际环境中运行(显示包含有用图像内容的表面,更新显示,实际应用效果)或作为测试(运行pixels2d而不是其他任何内容),Python的内存使用量急剧增长(大约4Mb /秒,最快10Mb /秒,与其他波动无关),直到它无法占用更多。

如果我没有将pygame.surfarray.pixels2d(testsurf)分配给变量并且如果我不以任何方式更改它,则不会发生此问题,这意味着使用该函数而没有其内存使用膨胀的唯一方法是调用它原样,没有效果。这意味着我可以看到它,没有别的。即使是简单的值赋值pygame.surfarray.pixels2d(testsurf)[0,0] = 0也会导致内存问题。

我尝试了很多不同的解决方案:

  • 在实际测试中,使用testarray = pygame.surfarray.array2d(testsurf)代替pixels2d视图,然后使用pygame.pixels2d(testsurf)[...] = testarray将数组应用回目标曲面,
  • 更改testarray = pygame.surfarray.pixels2d(testsurf).copy()并将该数组应用于目标表面,如上所述
  • 使用pygame.surfarray.pixels2d(testsurf)代替testarray,以便永远不会将视图分配给变量。
  • 在上述每一项中,添加或删除del testarray均无效。

在所有情况下,Python的内存使用(报告给任务管理器)几乎不间断地增长,直到我关闭程序关闭/重启IDLE,此时内存被释放。如果循环停止但shell未关闭或重新启动,则继续保持存储器。

我是否错误地使用pixels2d?是否有一些我需要调用的函数触发没有发生的垃圾收集?是否所有旧testarray对象都被保留在某处而不是被重新分配或删除(公开或在垃圾回收期间)?在某个地方,某些东西正在填满数组(或者我想其他一些数据),我不知道在哪里或如何做,或者该怎么做。

我正在使用Python2并安装了NumPy

== 更新 ==

看起来某处某处保留了对视图的引用:

from sys import getrefcount
for n in range(25):
    testarray = pygame.surfarray.pixels2d(testsurf)
    del testarray

>>> getrefcount(testsurf)
... 27

我还发现多年前的this链接以pixels2d以及pixels3d已解决问题的消息结束,但此处为。{1}}。我的pygame版本是1.9.2pre;当然不是四岁。

== 更新 ==

看起来testarray = numpy.array(testsurf.get_view()) 会创建这些幻像引用,所以它不一定是surfarray的缺陷,而是与Surfaces本身有关...

1 个答案:

答案 0 :(得分:0)

此内存泄漏已在Pygame的1.9.1release版本或至少Python2.7 / Windows版本中得到纠正。安装此版本,问题就会消失。

1.9.2pre可能是模块的实验版本,从未修复过错误。尝试修复此版本中的问题可能难以想象,因为问题似乎出现在Pygame的Surface模块中(据我所知),实际上是{{1} }。要纠正它,它需要对C组件进行逆向工程,纠正缺陷,然后重新打包它 - 不用说,除非你先写下这个东西,还要做更多的工作而不仅仅是向上(向下? )评分为1.9.1release(如果你仔细查看the files on the Pygame downloads FTP link,你会发现实际上是半年或更长更新而不是1.9.2pre)。它还解释了那个小小的" pre"在版本号的末尾。

** - 更新 - **

Here's the issue report,如果你喜欢这种事情。