代码之家  ›  专栏  ›  技术社区  ›  Dan Sosedoff

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

  •  15
  • Dan Sosedoff  · 技术社区  · 17 年前

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

    4 回复  |  直到 11 年前
        1
  •  11
  •   Matt    17 年前

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

    当您将图像变量重新分配给新图像时,只需使用GC。开始确保从内存中释放旧引用。

    在RMagick的后续版本中,我也相信你也可以称之为destroy!当您完成处理后,将显示在图像上。

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

        2
  •  8
  •   OpenCoderX    12 年前

    使用RMagick时,重要的是要记住在完成后销毁图像,否则在处理大型图像集时会填充/tmp dir。例如,您必须调用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
    
        3
  •  5
  •   Skade    17 年前

    实际上,这并不是Ruby特有的问题,其他解释器也有同样的问题。具体的问题是Ruby的GC只看到由Ruby本身分配的内存,而不是由外部库分配的内存(使用Rubys内存管理设施的库除外)。因此,Ruby内存空间中的ImageMagick对象非常小,但ImageMagick管理的空间中的图像很大。因此,这本身不是泄漏,但其行为类似于泄漏。

    还有一个图书馆叫 MagickWand 作者蒂莫西·保罗·亨特(RMagick的作者),试图解决这些问题并创建更好的API。不过,它是alpha版本,需要一个新版本的ImageMagick。

        4
  •  1
  •   Zoltán Takács    6 年前

    我想 RMAGICK_ENABLE_MANAGED_MEMORY = true GC.start 是你需要的。

    MANAGED_MEMORY
    
    If true, RMagick is using Ruby managed memory for all allocations. If false, 
    RMagick allocates memory for objects directly from the operating system. You can 
    enable RMagick to use Ruby managed memory (when built with ImageMagick 6.4.0-11 
    and later) by setting
    RMAGICK_ENABLE_MANAGED_MEMORY = true
    before requiring RMagick.
    

    https://rmagick.github.io/constants.html

    然而 image.destroy! 其本身足以稳定内存消耗。

        5
  •  -1
  •   cjs    17 年前

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

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

    这是假设工作项相当大,如果您使用ImageMagick,几乎可以肯定。如果没有,您会发现生成新进程和让Ruby解释器重新解析整个程序的开销开始变得有点太大。您可以通过让程序在重新执行之前执行更多的工作单元(例如,10或100)来解决这个问题。