如何防止 pygame.surfarray.pixels2d 中的内存泄漏?
How can I prevent memory leaks in pygame.surfarray.pixels2d?
我有一个生成器,它使用 pygame.surfarray.pixels2d()
将一系列简单的翻译效果应用于图像 Surface
。然而,我很快发现,随着循环的循环,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 的内存使用(如报告给任务管理器的那样)几乎不停地增长,直到我关闭程序 and close/restart 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 link,它以一条消息结尾,指出 pixels2d
和 pixels3d
的问题已解决,但这里是.我的 pygame 版本是 1.9.2pre
;肯定不是四岁。
== 更新 ==
看起来像 testarray = numpy.array(testsurf.get_view())
也 创建了这些幻象引用,所以它不一定是 surfarray
的缺陷,而是与 Surfaces 本身有关.. .
此内存泄漏已在 Pygame 的 1.9.1release
版本或至少 Python2.7/Windows 版本中得到纠正。安装这个版本,问题就会消失。
1.9.2pre
可能是该模块的实验版本,从未修复过错误。尝试修复此版本中的问题可能难以想象,因为问题似乎出在 Pygame 的 Surface
模块中,(据我所知)实际上是在C
。要更正它,需要对 surface.pyd
组件进行逆向工程,更正缺陷,然后重新打包它——不用说,除非你一开始就写了东西,否则比向上(向下? ) 升级到 1.9.1release(如果你仔细观察 the files on the Pygame downloads FTP link,你会发现实际上比 1.9.2pre 更新了 半年或更长时间)。它还解释了版本号末尾的小 "pre"。
** -- 更新 -- **
Here's the issue report,如果你喜欢这种东西
我有一个生成器,它使用 pygame.surfarray.pixels2d()
将一系列简单的翻译效果应用于图像 Surface
。然而,我很快发现,随着循环的循环,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 的内存使用(如报告给任务管理器的那样)几乎不停地增长,直到我关闭程序 and close/restart 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 link,它以一条消息结尾,指出 pixels2d
和 pixels3d
的问题已解决,但这里是.我的 pygame 版本是 1.9.2pre
;肯定不是四岁。
== 更新 ==
看起来像 testarray = numpy.array(testsurf.get_view())
也 创建了这些幻象引用,所以它不一定是 surfarray
的缺陷,而是与 Surfaces 本身有关.. .
此内存泄漏已在 Pygame 的 1.9.1release
版本或至少 Python2.7/Windows 版本中得到纠正。安装这个版本,问题就会消失。
1.9.2pre
可能是该模块的实验版本,从未修复过错误。尝试修复此版本中的问题可能难以想象,因为问题似乎出在 Pygame 的 Surface
模块中,(据我所知)实际上是在C
。要更正它,需要对 surface.pyd
组件进行逆向工程,更正缺陷,然后重新打包它——不用说,除非你一开始就写了东西,否则比向上(向下? ) 升级到 1.9.1release(如果你仔细观察 the files on the Pygame downloads FTP link,你会发现实际上比 1.9.2pre 更新了 半年或更长时间)。它还解释了版本号末尾的小 "pre"。
** -- 更新 -- **
Here's the issue report,如果你喜欢这种东西