如何在Ruby中处理RMagick中的内存泄漏?

我正在使用Merb开发Web应用程序,我正在寻找一些安全稳定的图像处理库。 我以前在php中使用Imagick,然后转移到ruby并开始使用RMagick。 但有一个问题。 长时间运行的脚本导致内存泄漏。 有两种解决方案存在,但我不知道哪一种最稳定。 所以你怎么看?

现在,我的应用程序使用我编写的内部API来处理PHP中的图像。 它与其他应用程序一起运行在单独的服务器上,因此它不是一个大问题。 但我认为它不是一个好的架构。

无论如何,我会考虑任何实用技巧。

我也遇到过这个问题 – 解决方法是强制垃圾收集。

将图像变量重新分配给新图像后,只需使用GC.start确保从内存中释放旧引用。

在RMagick的后期版本中,我也相信你也可以召唤毁灭! 在完成处理后的图像上。

两者的组合可能会确保你被覆盖,但我不确定现实生活对性能的影响(我认为在大多数情况下它可以忽略不计)。

或者,您可以使用mini-magick ,它是ImageMagick命令行客户端的包装器。

使用RMagick时,重要的是要记住在完成后销毁图像,否则在处理大量图像时会填充/ tmp目录。 例如,你必须调用destroy!

require 'RMagick' Dir.foreach('/home/tiffs/') do |file| next if file == '.' or file == '..' image = Magick::Image.read(file).first image.format = "PNG" image.write("/home/png/#{File.basename(file, '.*')}.png") image.destroy! end 

实际上,它并不是真正的Ruby特定问题,其他口译员也同样如此。 具体问题是Ruby的GC只看到由Ruby本身分配的内存,而不是外部库(除了使用Rubys内存管理工具的库的明显例外)。 因此,Ruby内存空间中的ImageMagick-Object非常小,但ImageMagick管理的空间中的图像很大。 所以,这本身并不是泄漏,但它的行为就像一个。 如果您的进程保持在一定限度(标准为8MB),Rubys垃圾收集器永远不会启动。 由于ImageMagick从不在Ruby空间中创建大型对象,因此它可能永远不会开始使用。因此,要么使用提出的生成新进程的方法,要么使用exec。 另一个相当漂亮的是在后端拥有一个图像处理服务,用于执行每项任务。 另一个是进行某种监控,每隔一段时间启动一次GC。

另一个名为MagickWand的图书馆由Timothy Paul Hunter(RMagick的作者)试图解决这些问题并创建一个更好的API。 它是alpha版本,但需要一个相当新的ImageMagick版本。

这不是由于ImageMagick; 它归功于Ruby本身,这是一个众所周知的问题。 我的建议是将你的程序分成两部分:一个长期运行的部分,它只分配很少的内存,只处理系统的控制,另外一个程序实际上处理工作。 长时间运行的控制过程应该足以找到它产生的子进程的一些工作,并且子进程应该对该特定工作项执行所有处理。

另一种选择是将两者结合起来,但在工作单元完成后,使用exec用同一程序的新启动版本替换您的进程,该程序将搜索另一个工作项,处理它并再次执行。

这假设工作项目相当大,如果您使用ImageMagick,它们几乎肯定是。 如果他们不是,你会发现产生一个新进程并让Ruby解释器重新解析整个程序的开销会开始变得有点过大。 您可以通过让程序在重新执行之前执行更多工作单元(例如,十个或一百个)来处理此问题。

Interesting Posts