2012-04-03 22 views
6

Tengo que renderizar algo con Imagick en PHP CLI. Me he dado cuenta de que cada 3-5 días la memoria del servidor se llena, por lo que ni siquiera puedo connet a través de ssh o ftp.PHP Imagick memory leak

con memory_get_usage() Arrastré la fuga de memoria a la parte de imagick del script. el guión es como la siguiente:

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

que destruyen la imagen de referencia, y desarmar el imagick y el objeto ImagickDraw, pero el guión no liberará cualquier memoria. El método setFillColor() toma la mayor cantidad de memoria

¿Puedo hacer algo más para liberar el espacio utilizado por imageick?

image of the memory consumption

Respuesta

15

imagick utiliza una biblioteca compartida y su uso de memoria está fuera del alcance de PHP, por lo que ajustar la memoria PHP y la recolección de basura no ayudará.

Tuve el mismo problema, tratando de manejar una imagen de tiff de varias páginas con 50 (!) Páginas de 3000x2000 píxeles. La solución es tener imagick poner su memoria caché de píxeles en el disco.

La adición de este antes de crear el objeto Imagick resuelto el problema para mí:

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

El objetivo es hacer imagick poner su caché de píxeles en el disco en lugar de en la memoria RAM. El lugar predeterminado parece ser files/tmp/magick-XXnnnnn, así que asegúrese de que/tmp no esté en shmfs/ramdisk, o cambie el directorio temporal que usa imagick.

Otros límites de recursos para investigar: imagick::RESOURCETYPE_DISK, imagick::RESOURCETYPE_FILE y imagick::RESOURCETYPE_AREA. Se describen en el imagick::getResourceLimit() manual page (no tan bien en la página para setResourceLimit()).

En mi bucle de manejo de imágenes, tengo set_time_limit(300), ya que el script tarda años en procesar esta enorme imagen (cuando descomprime).


EDIT: En versiones recientes, setResourceLimit() no debería ser llamado como un método estático, sino en el objeto real en lugar, como por ejemplo:

$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

ya me rendí en este problema. pero esta solución funciona genial gracias – Slemgrim

+0

¿Alguien sabe algo similar en Java? – krakover

+0

¿Entonces llenará el disco en lugar de la RAM? ¿Qué es este caché? –

1

Xdebug no era capaz de ayudarme .. así que decidió hacer mirar hacia fuera para otra solución. me ocurrió con el uso de la imagen mágica directa:

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

estas soluciones funciona manera más suave entonces el imagick uno. pero no me gusta el código propenso a errores.

+0

Hmm, así que ciertamente funciona, pero aparte de la fealdad de llamar comandos de shell dentro de php, en algunos servidores de producción, el ejecutivo está realmente deshabilitado por razones de seguridad. – Toumal

3

Sé que esto es viejo, pero me encontré con el mismo problema y llamando al $im->clear() en lugar de $im->destroy() corrigió la fuga de memoria por mí.

De acuerdo con documentationImagick::destroy() has been deprecated in favor of Imagick::clear(). Por lo tanto, se debe usar clear().