info form debug php debugging memory methodology

form - ¿Cómo se solucionan los problemas de php "Sin memoria"?



xdebug php info (6)

Consulte la documentación de la función memory_get_usage() para ver el uso de memoria en tiempo de ejecución.

Recientemente he tenido algunos problemas con los límites de memoria de PHP:

Sin memoria (asignado 22544384) (intentado asignar 232 bytes)

Estos son bastante molestos para depurar ya que no me queda mucha información sobre qué causó el problema.

Agregar una función de apagado ha ayudado

register_shutdown_function(''shutdown'');

luego, usando error_get_last (); Puedo obtener información sobre el último error, en este caso, el error fatal "Memoria insuficiente", como el número de línea y el nombre del archivo php.

Esto es bueno y todo, pero mi programa php está fuertemente orientado a objetos. Un error en el fondo de la pila no me dice mucho sobre la estructura de control o la pila de ejecución en el momento del error. He intentado con debug_backtrace(), pero eso solo me muestra la pila durante el cierre, no la pila en el momento del error.

Sé que puedo elevar el límite de memoria usando ini_set o modificando php.ini, pero eso no me acerca más a la idea de averiguar qué consume tanta memoria o cuál es mi flujo de ejecución durante el error.

¿Alguien tiene una buena metodología para depurar errores de memoria en programas avanzados orientados a objetos PHP?


El sitio web " IF! 1 0 " proporciona una clase MemoryUsageInformation fácil de usar. Es muy útil para depurar fugas de memoria.

<?php class MemoryUsageInformation { private $real_usage; private $statistics = array(); // Memory Usage Information constructor public function __construct($real_usage = false) { $this->real_usage = $real_usage; } // Returns current memory usage with or without styling public function getCurrentMemoryUsage($with_style = true) { $mem = memory_get_usage($this->real_usage); return ($with_style) ? $this->byteFormat($mem) : $mem; } // Returns peak of memory usage public function getPeakMemoryUsage($with_style = true) { $mem = memory_get_peak_usage($this->real_usage); return ($with_style) ? $this->byteFormat($mem) : $mem; } // Set memory usage with info public function setMemoryUsage($info = '''') { $this->statistics[] = array(''time'' => time(), ''info'' => $info, ''memory_usage'' => $this->getCurrentMemoryUsage()); } // Print all memory usage info and memory limit and public function printMemoryUsageInformation() { foreach ($this->statistics as $satistic) { echo "Time: " . $satistic[''time''] . " | Memory Usage: " . $satistic[''memory_usage''] . " | Info: " . $satistic[''info'']; echo "/n"; } echo "/n/n"; echo "Peak of memory usage: " . $this->getPeakMemoryUsage(); echo "/n/n"; } // Set start with default info or some custom info public function setStart($info = ''Initial Memory Usage'') { $this->setMemoryUsage($info); } // Set end with default info or some custom info public function setEnd($info = ''Memory Usage at the End'') { $this->setMemoryUsage($info); } // Byte formatting private function byteFormat($bytes, $unit = "", $decimals = 2) { $units = array(''B'' => 0, ''KB'' => 1, ''MB'' => 2, ''GB'' => 3, ''TB'' => 4, ''PB'' => 5, ''EB'' => 6, ''ZB'' => 7, ''YB'' => 8); $value = 0; if ($bytes > 0) { // Generate automatic prefix by bytes // If wrong prefix given if (!array_key_exists($unit, $units)) { $pow = floor(log($bytes) / log(1024)); $unit = array_search($pow, $units); } // Calculate byte value by prefix $value = ($bytes / pow(1024, floor($units[$unit]))); } // If decimals is not numeric or decimals is less than 0 // then set default value if (!is_numeric($decimals) || $decimals < 0) { $decimals = 2; } // Format output return sprintf(''%.'' . $decimals . ''f '' . $unit, $value); } }


Me pregunto es quizás su metodología de puntos de vista de pensamiento es defectuoso aquí.

La respuesta básica a su pregunta: ¿cómo puedo averiguar dónde está ocurriendo este error? - ya ha sido respondida; usted sabe lo que está causando eso.

Sin embargo, este es uno de esos casos en los que el error desencadenante no es realmente el problema; sin duda, ese objeto de 232 bytes no es en absoluto su problema. Son los 20 + Megs los que se asignaron antes.

Se han publicado algunas ideas que pueden ayudarlo a rastrear eso; realmente necesita buscar "nivel superior" aquí, en la arquitectura de la aplicación, y no solo en funciones individuales.

Es posible que su aplicación requiera más memoria para hacer lo que hace, con la carga de usuario que tiene. O puede ser que haya algunos cerdos de memoria reales que son innecesarios, pero debe saber qué es necesario o no para responder esa pregunta.

Eso básicamente significa ir línea por línea, objeto por objeto, perfilar según sea necesario, hasta que encuentre lo que busca; grandes usuarios de memoria. Tenga en cuenta que puede que no haya uno o dos objetos grandes ... ¡si fuera tan fácil! Una vez que encuentre los "cerdos de la memoria", tendrá que averiguar si pueden ser optimizados. Si no, entonces necesitas más memoria.


Use xdebug para usar la memoria de perfil.


Memprof es una extensión de php que ayuda a encontrar esos fragmentos de comedores de memoria, especialmente en códigos orientados a objetos.

Este tutorial adaptado es bastante útil.

Nota: Intenté sin éxito compilar esta extensión para Windows. Si lo intenta, asegúrese de que su php no sea seguro para subprocesos. Para evitar algunos dolores de cabeza te sugiero que lo uses en entornos * nix.

Otro enlace interesante fue un slideshare describe cómo php maneja la memoria. Le da algunas pistas sobre el uso de memoria de su script.


echo ''<pre>''; $vars = get_defined_vars(); foreach($vars as $name=>$var) { echo ''<strong>'' . $name . ''</strong>: '' . strlen(serialize($var)) . ''<br />''; } exit(); /* ... Code that triggers memory error ... */

Utilizo esto para imprimir una lista de variables asignadas actualmente justo antes de una sección problemática de mi código, junto con una estimación (muy) aproximada del tamaño de la variable. Regrese y unset todo lo que no sea necesario en y más allá del punto de interés.

Es útil cuando instalar una extensión no es una opción.

Puede modificar el código anterior para usar memory_get_usage de una manera que le proporcione una estimación diferente de la memoria en una variable, sin estar seguro de si sería mejor o peor.