Утечка памяти в PHP Imagick

Я должен сделать что-то с Imagick на PHP CLI. Я заметил, что каждые 3-5 дней память сервера переполняется, поэтому я даже не могу подключиться через ssh или ftp.

с помощью memory_get_usage() я рассказал об утечке памяти в воображаемой части скрипта. скрипт выглядит примерно так:

$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?

изображение потребления памяти

3 ответа

Решение

imagick использует разделяемую библиотеку, и ее использование памяти недоступно для PHP, поэтому настройка памяти PHP и сборка мусора не помогут.

Я сам столкнулся с той же проблемой, пытаясь обработать многостраничное изображение с 50 (!) Страницами размером 3000x2000 пикселей. Решение состоит в том, чтобы 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 поместил свой пиксельный кеш на диск, а не в оперативную память. Кажется, что местом по умолчанию являются файлы /tmp/magick-XXnnnnn, поэтому убедитесь, что / tmp отсутствует в shmfs/ramdisk, или измените временный каталог, используемый imagick.

Другие ограничения для расследования: imagick::RESOURCETYPE_DISK, imagick::RESOURCETYPE_FILE, а также imagick::RESOURCETYPE_AREA, Они описаны на странице справки imagick::getResourceLimit() (не очень хорошо на странице для 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);

Я знаю, что это старый, но я столкнулся с той же проблемой и звоню $im->clear() вместо $im->destroy() исправил утечку памяти для меня.

Согласно документации Imagick::destroy() has been deprecated in favor of Imagick::clear(), Так clear() должен быть использован.

Вы можете использовать это.

Обратите внимание, что 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

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

Это решение работает намного лучше, чем воображаемое. но мне не нравится подверженный ошибкам код.

Другие вопросы по тегам