2011-06-13 14 views
24

Estoy trabajando con una gran matriz que es un mapa de altura, 1024x1024 y, por supuesto, estoy atascado con el límite de memoria. En mi máquina de prueba puedo aumentar el límite de memoria a 1 gb si quiero, pero en mi VPS pequeño con solo 256 RAM, no es una opción.Optimización de memoria en PHP array

He estado buscando en stack y google y encontré varios "bueno, estás usando PHP no porque la eficiencia de la memoria, lo dejé y reescribí en C++" y sinceramente, está bien y reconozco que PHP adora la memoria.

Pero, al profundizar más en la administración de la memoria PHP, no encontré qué memoria consume cada tipo de datos. O si la conversión a otro tipo de datos reduce el consumo de memoria.

La única técnica de "optimización" que encontré fue desarmar variables y matrices, eso es todo.

Convertir el código a C++ utilizando algunos analizadores de PHP resolvería el problema?

Gracias!

+3

Las matrices realmente tienen mucha memoria en PHP (ya que en realidad son diccionarios). Si puede renunciar a una (¡mucha) velocidad, puede [falsificar matrices binarias como en C] (http://stackoverflow.com/questions/5505124/cheating-php-integers/5505643#5505643), también para estructuras 2D Supongo. Pero tal vez realmente desee investigar el compilador HipHop PHP a C++ (https://github.com/facebook/hiphop-php/wiki/). – mario

+0

Cada variable en PHP tiene una sobrecarga asociada a ella. No solo tiene que almacenarse el valor de la variable, sino también el nombre, tipo, etc. de la variable ... Incluso un simple '$ x [1] = 2;' tiene un gran cuerpo de cosas adicionales que lo siguen. –

+0

¿Qué tal una extensión de php? – Bytemain

Respuesta

44

Si quiere una matriz indexada real, use SplFixedArray. Usa menos memoria. Además, PHP 5.3 tiene un recolector de basura mucho mejor.

Aparte de eso, bueno, PHP usará más memoria que un equivalente C/C++ escrito más cuidadosamente.

uso de memoria para 1024x1024 matriz de enteros:

  • matriz estándar: 218.756.848
  • SplFixedArray: 92.914.208

medido por memory_get_peak_usage()

$array = new SplFixedArray(1024 * 1024); // array(); 
for ($i = 0; $i < 1024 * 1024; ++$i) 
    $array[$i] = 0; 

echo memory_get_peak_usage(); 

Tenga en cuenta que la misma matriz en C usar enteros de 64 bits sería 8M.

Como han sugerido otros, podría empaquetar los datos en una cadena. Esto es más lento pero mucho más eficiente de la memoria. Si el uso de valores de 8 bits que es muy fácil:

$x = str_repeat(chr(0), 1024*1024); 
$x[$i] = chr($v & 0xff); // store value $v into $x[$i] 
$v = ord($x[$i]);  // get value $v from $x[$i] 

Aquí la memoria sólo habrá aproximadamente 1,5 MB (es decir, cuando se considera toda la sobrecarga de PHP con sólo esta matriz de cadenas entero).

Por el gusto de hacerlo, creé un punto de referencia simple para crear enteros de 824 bits de 1024x1024 y luego recorrerlos una vez. Las versiones empaquetadas usaron ArrayAccess para que el código de usuario tuviera el mismo aspecto.

    mem write read 
array    218M 0.589s 0.176s 
packed array  32.7M 1.85s 1.13s 
packed spl array 13.8M 1.91s 1.18s 
packed string  1.72M 1.11s 1.08s 

Las matrices utilizadas envasados ​​nativos enteros de 64 bits (sólo embalaje 7 bytes de evitar el trato con los datos firmados) y la cadena de empaquetado utilizados ord y chr. Obviamente, los detalles de implementación y las especificaciones de la computadora afectarán un poco las cosas, pero espero que obtenga resultados similares.

Por lo tanto, aunque la matriz era 6 veces más rápida, también usaba 125 veces la memoria como la siguiente mejor alternativa: cadenas empaquetadas. Obviamente, la velocidad es irrelevante si se está quedando sin memoria. (Cuando usé cadenas empaquetadas directamente sin una clase ArrayAccess, solo fueron 3 veces más lentas que las matrices nativas).)

En resumen, usaría algo más que PHP puro para procesar estos datos si la velocidad es una preocupación.

+0

+1 Además, emular los índices de matriz y usar el empaque puede reducir aún más el uso de memoria, si corresponde. P.ej. si cada valor del mapa de altura es de solo 8 bits, el * uso de la memoria debería ser considerablemente menor * cuando se empaqueta a 32 bits (o 64 bits dependiendo del bitness de PHP). La ganancia exacta en eficiencia varía debido al tamaño de la carga útil/utilización frente a los gastos generales de mantenimiento de los valores PHP utilizados. (Creo que hay 4 bytes de "sobrecarga" por valor entero, pero no estoy del todo seguro.) –

+0

Aparentemente hay más de 4 bytes de sobrecarga ... [esta publicación] (http://stackoverflow.com/questions/5972170/what-is-the-overhead-of-using-php-int) sugiere que puede tomar más de 36 (o 72 en x64) bytes solo por un valor trivial. Esto indica que es * muy beneficioso * (en términos de uso de memoria) para empacar. Asumiendo una entrada de 8 bits y un arco de 32 bits, 4 valores tomarían ~ 36bytes vs. ~ 144bytes si se empaquetan mientras que en una máquina x64 ¡8 valores tomarían ~ 72bytes contra ~ 576bytes! (Yikes!) –

+0

Entonces, en conclusión ... con el empaque, los valores de 8 bits se amortizan a ~ 9 bytes para una estimación de 9 MB de sobrecarga/datos del objeto, excluyendo la memoria requerida para su inclusión en la matriz, etc. - descuartizar los números publicados es ~ 22.5MB de uso total. (Tal empaque puede parecer demasiado optimizador, pero considerando que el objetivo está limitado a 256MB de RAM ... ;-) –

11

Además de la respuesta aceptada y sugerencias en los comentarios, me gustaría sugerir PHP Judy array implementation.

Las pruebas rápidas arrojaron resultados interesantes. Una matriz con 1 millón de entradas con una estructura de datos de matriz PHP normal toma ~ 200 MB. SplFixedArray usa alrededor de 90 megabytes. Judy usa 8 megas Tradeoff está en el rendimiento, Judy tarda aproximadamente el doble del tiempo de implementación regular de la matriz php.

+0

Lo verifico, ¡lindo! En mi caso, puedo vivir con un golpe de rendimiento para salvar un poco de ram. –

+0

¡Exactamente lo que necesito! [Judy Array] (http://en.wikipedia.org/wiki/Judy_array) es increíble. Alto rendimiento y bajo uso de memoria. – FlycKER

+0

@FlycKER - Me alegro de que alguien haya decidido utilizar esta impresionante implementación de matriz :) –