【问题标题】:PHP Imagick memory leakPHP Imagick 内存泄漏
【发布时间】:2012-04-17 02:19:01
【问题描述】:

我必须在 PHP CLI 上使用 Imagick 渲染一些东西。 我注意到每隔 3-5 天服务器内存就会满,所以我什至无法通过 ssh 或 ftp 连接。

使用 memory_get_usage() 我将内存泄漏减少到脚本的 imagick 部分。 脚本看起来像这样:

$sourceImg = 'source.png';
$destImg = 'dest.png';
$background ='#00ff00';

$im = new Imagick();
$im->pingImage($sourceImg);
$im->readImage($sourceImg); 
$draw = new ImagickDraw();

for($i=1;$i<=5;$i++){
    $draw->setFillColor( $background);
    $draw->rectangle( 10*$i+5, 10, 10*$i+10, 20);
} 

$im->drawImage( $draw );
$im->writeImage( $destImg );
$im->destroy();

unset($im,$draw);

我销毁图像引用,并取消设置 imagick 和 imagickDraw 对象,但脚本不会释放任何内存。 setFillColor() 方法占用内存最多

我可以做其他事情来释放 imageick 使用的空间吗?

image of the memory consumption

【问题讨论】:

    标签: php memory-leaks imagick


    【解决方案1】:

    xdebug 无法帮助我.. 所以我决定寻找另一种解决方案。 我想出了直接使用图像魔术:

    $sourceImg = 'source.png';
    $destImg = 'dest.png';
    $background ='#00ff00';
    
    $command = "convert {$sourceImg}";
    $out = array();
    
    for($i=1;$i<=5;$i++){
        $command .= " -fill \"{$background}\" ";
        $command .= " -draw 'rectangle {$x1},{$y1} {$x2},{$y2}'";
    } 
    
    $command .= " {$destImg}";
    exec($command,$out);
    

    这个解决方案比想象中的解决方案更流畅。但我不喜欢容易出错的代码。

    【讨论】:

    • 嗯,它确实可以工作,但是除了从 php 中调用 shell 命令的丑陋之外,出于安全原因,在某些生产服务器上实际上禁用了 exec。
    【解决方案2】:

    imagick 使用一个共享库,它的内存使用量对于 PHP 来说是遥不可及的,因此调整 PHP 内存和垃圾收集将无济于事。

    我自己也遇到了同样的问题,试图处理一个 50 (!) 页 3000x2000 像素的多页 tiff 图像。 解决方案是让 imagick 将其像素缓存放在磁盘上。

    在创建 Imagick 对象之前添加它为我解决了这个问题:

    // pixel cache max size
    IMagick::setResourceLimit(imagick::RESOURCETYPE_MEMORY, 256);
    // maximum amount of memory map to allocate for the pixel cache
    IMagick::setResourceLimit(imagick::RESOURCETYPE_MAP, 256);
    

    目标是让 imagick 将其像素缓存放在磁盘上而不是 RAM 中。默认位置似乎是文件 /tmp/magick-XXnnnnn,因此请确保 /tmp 不在 shmfs/ramdisk 上,或者更改 imagick 使用的临时目录。

    要调查的其他资源限制:imagick::RESOURCETYPE_DISKimagick::RESOURCETYPE_FILEimagick::RESOURCETYPE_AREA。 它们在imagick::getResourceLimit() manual page 中有描述(在setResourceLimit() 的页面中不是很好)。

    在我的图像处理循环中,我有set_time_limit(300),因为脚本需要很长时间才能处理这个巨大的(解压缩时)图像。


    编辑: 在最近的版本中,setResourceLimit() 不应作为静态方法调用,而是在实际对象上调用,例如:
    $im->setResourceLimit(imagick::RESOURCETYPE_MEMORY, 256);
    $im->setResourceLimit(imagick::RESOURCETYPE_MAP, 256);
    $im->setResourceLimit(imagick::RESOURCETYPE_AREA, 1512);
    $im->setResourceLimit(imagick::RESOURCETYPE_FILE, 768);
    $im->setResourceLimit(imagick::RESOURCETYPE_DISK, -1);
    

    【讨论】:

    • 我已经放弃了这个问题。但这个解决方案效果很好。谢谢
    • 有谁知道 Java 中类似的东西吗?
    • 所以它会填满磁盘而不是内存?这是什么缓存?
    • 是的。当 RAM 太小时,将像素缓存放在磁盘上是必要的。将 ImageMagick 的像素缓存视为用于图像处理和临时存储的虚拟内存。
    • 注意:根据 RESOURCETYPE 常量文档,限制应以字节为单位,而不是兆字节,因此如果您希望限制为 256 MB,则 256 应为 256 * 1024 * 1024。
    【解决方案3】:

    我知道这很旧,但我遇到了同样的问题,并调用 $im-&gt;clear() 而不是 $im-&gt;destroy() 为我修复了内存泄漏。

    根据documentationImagick::destroy() has been deprecated in favor of Imagick::clear()。所以应该使用clear()

    【讨论】:

      【解决方案4】:

      你可以用这个。

      请注意,根据文档,clear() 优先于 destroy() 以释放内存使用。

      // clear temp files
      $imagick_image->clear(); // in your case "$img->clear();"
      

      您也可以运行 cron 来为您删除临时文件,否则您的服务器可能会崩溃。这不是php代码,是命令行代码。

      # linux command
      find /tmp/ -name "magick-*" -type f -delete
      
      # cron
      45 * * * * find /tmp/ -name "magick-*" -type f -delete
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-02-10
        • 2023-03-17
        • 2012-01-12
        • 2017-01-28
        • 2016-03-30
        • 1970-01-01
        • 2013-09-02
        • 2014-09-22
        相关资源
        最近更新 更多