Утечка памяти в 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);
Это решение работает намного лучше, чем воображаемое. но мне не нравится подверженный ошибкам код.