php - sobre - ¿Cómo determinar la huella de memoria(tamaño) de una variable?
sistemas de memoria pdf (11)
En respuesta a la respuesta de Tatu Ulmanens:
Cabe señalar que $start_memory
ocupará memoria ( PHP_INT_SIZE * 8
).
Entonces toda la función debería convertirse en:
function sizeofvar($var) {
$start_memory = memory_get_usage();
$var = unserialize(serialize($var));
return memory_get_usage() - $start_memory - PHP_INT_SIZE * 8;
}
Lamento agregar esto como una respuesta adicional, pero aún no puedo comentar una respuesta.
Actualización: el * 8 no es definate. Puede depender aparentemente de la versión de php y posiblemente en 64/32 bit.
¿Hay una función en PHP (o una extensión PHP) para averiguar cuánta memoria usa una variable determinada? sizeof
solo me dice la cantidad de elementos / propiedades.
memory_get_usage
ayuda porque me da el tamaño de memoria utilizado por todo el script. ¿Hay alguna manera de hacer esto para una sola variable?
Tenga en cuenta que esto se encuentra en una máquina de desarrollo, por lo que es factible cargar extensiones o herramientas de depuración.
La siguiente secuencia de comandos muestra el uso total de la memoria de una sola variable.
function getVariableUsage($var) {
$total_memory = memory_get_usage();
$tmp = unserialize(serialize($var));
return memory_get_usage() - $total_memory;
}
$var = "Hey, what''s you doing?";
echo getVariableUsage($var);
Mira esto
No hay una forma directa de obtener el uso de la memoria de una sola variable, pero como Gordon sugirió, puede usar memory_get_usage
. Eso devolverá la cantidad total de memoria asignada, por lo que puede usar una solución alternativa y medir el uso antes y después para obtener el uso de una sola variable. Esto es un poco raro, pero debería funcionar.
$start_memory = memory_get_usage();
$foo = "Some variable";
echo memory_get_usage() - $start_memory;
Tenga en cuenta que esto no es de ninguna manera un método confiable, no puede estar seguro de que nada más toque la memoria al asignar la variable, por lo que esto solo debe utilizarse como una aproximación.
En realidad, puede convertir eso en una función creando una copia de la variable dentro de la función y midiendo la memoria utilizada. No lo he probado, pero en principio, no veo nada malo con eso:
function sizeofvar($var) {
$start_memory = memory_get_usage();
$tmp = unserialize(serialize($var));
return memory_get_usage() - $start_memory;
}
No no hay. Pero puede serialize($var)
y comprobar el strlen
del resultado para una aproximación.
Nunca lo intenté, pero las trazas de xdebug.collect_assignment con xdebug.collect_assignment s pueden ser suficientes.
Probablemente necesites un Profiler de memoria. He reunido información de SO, pero he copiado algo importante que también puede serle útil.
Como probablemente sepa, Xdebug eliminó el soporte de perfiles de memoria desde la versión 2. *. Busque la cadena de "funciones eliminadas" aquí: http://www.xdebug.org/updates.php
Funciones eliminadas
Se eliminó la compatibilidad con el perfil de memoria, ya que no funcionaba correctamente.
Otras opciones de Profiler
php-memory-profiler
https://github.com/arnaud-lb/php-memory-profiler . Esto es lo que hice en mi servidor Ubuntu para habilitarlo:
sudo apt-get install libjudy-dev libjudydebian1
sudo pecl install memprof
echo "extension=memprof.so" > /etc/php5/mods-available/memprof.ini
sudo php5enmod memprof
service apache2 restart
Y luego en mi código:
<?php
memprof_enable();
// do your stuff
memprof_dump_callgrind(fopen("/tmp/callgrind.out", "w"));
Finalmente abra el archivo callgrind.out
con KCachegrind
Usando Google gperftools (¡recomendado!)
Antes que nada, instale los gperftools de Google descargándolos aquí: https://code.google.com/p/gperftools/
Entonces como siempre:
sudo apt-get update
sudo apt-get install libunwind-dev -y
./configure
make
make install
Ahora en tu código:
memprof_enable();
// do your magic
memprof_dump_pprof(fopen("/tmp/profile.heap", "w"));
Luego abre tu terminal e inicia:
pprof --web /tmp/profile.heap
pprof creará una nueva ventana en su sesión de navegador existente con algo como se muestra a continuación:
Xhprof + Xhgui (el mejor en mi opinión para perfilar tanto la CPU como la memoria)
Con Xhprof y Xhgui también puede hacer un perfil del uso de la CPU o simplemente del uso de la memoria, si ese es su problema en este momento. Es una solución muy completa, te da un control total y los registros se pueden escribir tanto en mongo como en el sistema de archivos.
Para más detalles, mira aquí .
Fuego negro
Blackfire es un perfilador PHP de SensioLabs, los chicos de Symfony2 https://blackfire.io/
Si usa puphpet para configurar su máquina virtual, le alegrará saber que es compatible ;-)
Xdebug y el uso de la memoria de seguimiento
XDEBUG2 es una extensión para PHP. Xdebug le permite registrar todas las llamadas a funciones, incluidos los parámetros y los valores de retorno a un archivo en diferentes formatos. Hay tres formatos de salida. Uno se entiende como un rastro legible por humanos, otro es más adecuado para programas de computadora ya que es más fácil de analizar, y el último usa HTML para formatear el trazado. Puede cambiar entre los dos formatos diferentes con la configuración. Un ejemplo estaría disponible aquí
para p
forp simple, no intrusivo, orientado a la producción, PHP profiler. Algunas de las características son:
medición de tiempo y memoria asignada para cada función
uso de CPU
número de archivo y línea de la llamada de función
salida como formato de evento de seguimiento de Google
leyenda de funciones
agrupación de funciones
alias de funciones (útiles para funciones anónimas)
DBG
DBG es un depurador de php con todas las funciones, una herramienta interactiva que le ayuda a depurar scripts de PHP. Funciona en un servidor WEB de producción y / o desarrollo y le permite depurar sus scripts local o remotamente, desde un IDE o consola y sus características son:
Depuración remota y local
Activación explícita e implícita
Pila de llamadas, incluidas llamadas a funciones, llamadas a métodos dinámicos y estáticos, con sus parámetros
Navegación a través de la pila de llamadas con la capacidad de evaluar variables en lugares correspondientes (anidados)
Paso / Salir / Paso / Funcionar con el cursor
Puntos de interrupción condicionales
Puntos de interrupción globales
Registro de errores y advertencias
Múltiples sesiones simultáneas para la depuración paralela
Soporte para front-ends GUI y CLI
Se admiten redes IPv6 e IPv4
Todos los datos transferidos por el depurador se pueden proteger opcionalmente con SSL
Puede optar por calcular la diferencia de memoria en un valor de retorno de devolución de llamada. Es una solución más elegante disponible en PHP 5.3+.
function calculateFootprint($callback) {
$startMemory = memory_get_usage();
$result = call_user_func($callback);
return memory_get_usage() - $startMemory;
}
$memoryFootprint = calculateFootprint(
function() {
return range(1, 1000000);
}
);
echo ($memoryFootprint / (1024 * 1024)) . '' MB'' . PHP_EOL;
Tuve un problema similar, y la solución que utilicé fue escribir la variable en un archivo y luego ejecutar filesize () en ella. Aproximadamente así (código no probado):
function getVariableSize ( $foo )
{
$tmpfile = "temp-" . microtime(true) . ".txt";
file_put_contents($tmpfile, $foo);
$size = filesize($tmpfile);
unlink($tmpfile);
return $size;
}
Esta solución no es terriblemente rápida porque involucra disco IO, pero debería proporcionarle algo mucho más exacto que los trucos de memory_get_usage. Solo depende de cuánta precisión requiera.
Ver:
-
memory_get_usage()
- Devuelve la cantidad de memoria asignada a PHP -
memory_get_peak_usage()
- Devuelve el pico de memoria asignado por PHP
Sin embargo, tenga en cuenta que esto no le dará el uso de memoria de una variable específica. Pero puede poner llamadas a estas funciones antes y después de asignar la variable y luego comparar los valores. Eso debería darte una idea de la memoria utilizada.
También puede echar un vistazo a la extensión PECL Memtrack , aunque la documentación es un poco escasa, si no digamos, prácticamente inexistente.
No puede calcular retrospectivamente la huella exacta de una variable, ya que dos variables pueden compartir el mismo espacio asignado en la memoria
Intentemos compartir memoria entre dos matrices, vemos que asignar la segunda matriz cuesta la mitad de la memoria de la primera. Cuando desarmamos el primero, casi toda la memoria sigue siendo utilizada por el segundo.
echo memory_get_usage()."/n"; // <-- 433200
$c=range(1,100);
echo memory_get_usage()."/n"; // <-- 444348 (+11148)
$d=array_slice($c, 1);
echo memory_get_usage()."/n"; // <-- 451040 (+6692)
unset($c);
echo memory_get_usage()."/n"; // <-- 444232 (-6808)
unset($d);
echo memory_get_usage()."/n"; // <-- 433200 (-11032)
Entonces no podemos concluir que la segunda matriz usa la mitad de la memoria, ya que se vuelve falsa cuando desarmamos la primera.
Para obtener una visión completa de cómo se asigna la memoria en PHP y para qué uso, le sugiero que lea el siguiente artículo: ¿Qué tan grandes son realmente las matrices (y los valores) de PHP? (Sugerencia: ¡GRANDE!)
Los Conceptos básicos de recuento de referencias en la documentación de PHP también contienen mucha información sobre el uso de la memoria y el recuento de referencias en el segmento de datos compartidos.
Las diferentes soluciones expuestas aquí son buenas para las aproximaciones, pero ninguna puede manejar la administración sutil de la memoria PHP.
- calcular espacio recién asignado
Si quiere el espacio recientemente asignado después de una asignación, entonces debe usar memory_get_usage()
antes y después de la asignación, ya que usarlo con una copia le da una visión errónea de la realidad.
// open output buffer
echo "Result: ";
// call every function once
range(1,1); memory_get_usage();
echo memory_get_usage()."/n";
$c=range(1,100);
echo memory_get_usage()."/n";
Recuerde que si desea almacenar el resultado de la primera memory_get_usage()
, la variable ya debe existir antes, y memory_get_usage()
debe llamarse otra vez anterior, y también cada otra función.
Si desea hacer eco como en el ejemplo anterior, su buffer de salida debe estar ya abierto para evitar la memoria contable necesaria para abrir el buffer de salida.
- calcular el espacio requerido
Si desea confiar en una función para calcular el espacio requerido para almacenar una copia de una variable, el siguiente código se ocupa de diferentes optimizaciones:
<?php
function getMemorySize($value) {
// existing variable with integer value so that the next line
// does not add memory consumption when initiating $start variable
$start=1;
$start=memory_get_usage();
// json functions return less bytes consumptions than serialize
$tmp=json_decode(json_encode($value));
return memory_get_usage() - $start;
}
// open the output buffer, and calls the function one first time
echo "./n";
getMemorySize(NULL);
// test inside a function in order to not care about memory used
// by the addition of the variable name to the $_GLOBAL array
function test() {
// call the function name once
range(1,1);
// we will compare the two values (see comment above about initialization of $start)
$start=1;
$start=memory_get_usage();
$c=range(1,100);
echo memory_get_usage()-$start."/n";
echo getMemorySize($c)."/n";
}
test();
// same result, this works fine.
// 11044
// 11044
Tenga en cuenta que el tamaño del nombre de la variable importa en la memoria asignada.
- ¡¡Revisa tu código !!
Una variable tiene un tamaño básico definido por la estructura interna de C utilizada en el código fuente de PHP. Este tamaño no fluctúa en el caso de los números. Para cadenas, agregaría la longitud de la cadena.
typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
zend_object_value obj;
} zvalue_value;
Si no tomamos en cuenta la inicialización del nombre de la variable, ya sabemos cuánto usa una variable (en el caso de números y cadenas):
44 bytes en el caso de los números
&más; 24 bytes en el caso de cadenas
&más; la longitud de la cadena (incluido el carácter NUL final)
(esos números pueden cambiar dependiendo de la versión de PHP)
Debe redondear a un múltiplo de 4 bytes debido a la alineación de la memoria. Si la variable está en el espacio global (no dentro de una función), también asignará 64 bytes más.
Entonces, si quiere usar uno de los códigos dentro de esta página, debe verificar que el resultado usando algunos casos de prueba simples (cadenas o números) coincida con esos datos teniendo en cuenta cada una de las indicaciones en esta publicación ($ _GLOBAL array, primera llamada de función, buffer de salida, ...)
function mesure($var){
$start = memory_get_usage();
if(is_string($var)){
$newValue = $var . '''';
}elseif(is_numeric($var)){
$newValue = $var + 0;
}elseif(is_object($var)){
$newValue = clone $var;
}elseif(is_array($var)){
$newValue = array_flip($var, []);
}
return memory_get_usage() - $start;
}