2012-04-03 18 views
6

PHP CLIでImagickで何かをレンダリングする必要があります。 私は3〜5日ごとにサーバのメモリがいっぱいになるので、sshやftp経由で接続することさえできないことに気付きました。PHP Imagickメモリリーク

with 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

答えて

15

imagickは共有ライブラリを使用しており、メモリ使用量がPHPの手に届かないため、PHPメモリとガベージコレクションのチューニングは役に立ちません。

私は同じ問題を自分で抱えていましたが、3000x2000ピクセルの50(!)ページのマルチページ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); 

目標は、ディスク上の代わりに、RAMにそのピクセル・キャッシュを置くimagickようにすることです。デフォルトの場所はfiles/tmp/magick-XXnnnnnのようですので、/ tmpがshmfs/ramdiskにないことを確認してください。また、imagickが使用する一時ディレクトリを変更してください。

調査対象の他のリソース制限は、imagick::RESOURCETYPE_DISK,imagick::RESOURCETYPE_FILEおよびimagick::RESOURCETYPE_AREAです。 これらはimagick::getResourceLimit() manual pageに記載されています(setResourceLimit()のページではあまりよくありません)。

私の画像処理ループでは、この巨大な(圧縮されていない)画像を処理するためにスクリプトに時間がかかりますので、set_time_limit(300)があります。


EDIT:最近のバージョンでは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); 
+0

私はすでにこの問題をあきらめました。しかし、このソリューションは素晴らしいです。ありがとう – Slemgrim

+0

誰もJavaで似たようなことを知っていますか? – krakover

+0

それでは、RAMの代わりにディスクをいっぱいにしますか?このキャッシュとは何ですか? –

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); 

このソリューションのImagick 1その後、道スムーズに動作します。私はエラーが発生しやすいコードが好きではありません。

+0

でも、確かにうまくいくのですが、PHPの中からシェルコマンドを呼び出すのは醜いのですが、実際の運用サーバーでは、セキュリティ上の理由からexecが実際には無効になっています。 – Toumal

3

私はこれが古いです知っているが、私はに走りました同じ問題があり、$im->destroy()の代わりに$im->clear()を呼び出すと、私のメモリリークが修正されました。

documentationImagick::destroy() has been deprecated in favor of Imagick::clear()によると、したがって、clear()を使用する必要があります。

関連する問題