65 votes

Besoin d'un tableau de structure en PHP avec un minimum d'utilisation de la mémoire

Dans mon script PHP, j'ai besoin de créer un tableau de >600 k entiers. Malheureusement, mes serveurs memory_limit est fixé à 32M donc, lors de l'initialisation de la matrice le script échoue avec message d'

Fatal error: Allowed memory size of 33554432 bytes exhausted (tried to allocate 71 bytes) in /home/www/myaccount/html/mem_test.php sur la ligne 8

Je suis conscient du fait que PHP ne pas stocker le tableau des valeurs comme la plaine des entiers, mais plutôt comme zvalues qui sont beaucoup plus gros que la plaine valeur entière (8 octets sur mon système 64 bits). J'ai écrit un petit script pour estimer la quantité de mémoire chaque entrée de ce tableau utilise et il s'avère que c'est assez exactement 128 octets. 128!!! J'aurais besoin d' >73M juste pour stocker le tableau. Malheureusement, le serveur n'est pas sous mon contrôle et je ne peut pas augmenter le memory_limit.

Ma question est, est-il possible en PHP pour créer un tableau-comme une structure qui utilise moins de mémoire. Je n'ai pas besoin de cette structure associative (plaine de l'indice d'accès est suffisant). Il également n'a pas besoin d'avoir un redimensionnement dynamique - je sais exactement comment big le tableau sera. Aussi, tous les éléments seraient du même type. Tout comme un bon vieux C-tableau.


Edit: Donc deceze's solution fonctionne out-of-the-box avec les nombres entiers de 32 bits. Mais même si vous êtes sur un système 64 bits, pack() ne semblent pas supporter les entiers 64 bits. Afin d'utiliser les entiers 64 bits dans mon tableau j'ai appliqué un peu de manipulation de bits. Peut-être au-dessous des extraits seront de l'aide à quelqu'un:

function push_back(&$storage, $value)
{
    // split the 64-bit value into two 32-bit chunks, then pass these to pack().
    $storage .= pack('ll', ($value>>32), $value);
}

function get(&$storage, $idx)
{
    // read two 32-bit chunks from $storage and glue them back together.
    return (current(unpack('l', substr($storage, $idx * 8, 4)))<<32 |
            current(unpack('l', substr($storage, $idx * 8+4, 4))));
}

59voto

deceze Points 200115

Le plus efficace en terme de mémoire que vous obtenez est probablement en stockant tout dans une chaîne de caractères, emballés dans du binaire, et l'utilisation indexation manuelle.

$storage = '';

$storage .= pack('l', 42);

// ...

// get 10th entry
$int = current(unpack('l', substr($storage, 9 * 4, 4)));

Cela peut être possible que si le "tableau" initialisation peut être fait d'un seul coup et vous êtes tout simplement la lecture de la structure. Si vous avez besoin de beaucoup de l'ajout à la chaîne, cela devient extrêmement inefficace. Cela peut être fait à l'aide d'un handle de ressource:

$storage = fopen('php://memory', 'r+');
fwrite($storage, pack('l', 42));
...

C'est très efficace. Vous pouvez alors lire ce mémoire tampon dans une variable et de l'utiliser comme une chaîne de caractères, ou vous pouvez continuer à travailler avec la ressource et de l' fseek.

28voto

Ryan Points 3020

Un PHP Judy Tableau va utiliser beaucoup moins de mémoire qu'un tableau PHP, et un SplFixedArray.

Je cite: "Un tableau avec 1 million d'entrées en utilisant un tableau PHP structure de données prend de 200 mo. SplFixedArray utilise environ 90 mo. Judy utilise 8 mégas. Compromis est dans la performance, Judy prend environ le double du temps régulier de tableau php de mise en œuvre."

11voto

Dysosmus Points 473

Vous pouvez essayer d'utiliser un SplFixedArray, c'est plus rapide et de prendre moins de mémoire (la doc commentaire dire ~30% de moins). Test ici et ici.

11voto

RJD22 Points 6024

Vous pouvez utiliser un objet, si possible. Elles utilisent souvent moins de mémoire que la matrice. Aussi SplFixedArray est une bonne option.

Mais cela dépend vraiment de la mise en œuvre de ce que vous devez faire. Si vous avez besoin d'une fonction pour retourner un tableau et sont à l'aide de PHP 5.5. Vous pouvez utiliser le générateur de rendement pour diffuser le tableau arrière.

5voto

dkellner Points 818

J'avais le stocker dans une chaîne fixe sur les décalages et les utiliser substr pour obtenir ce dont nous avions besoin. Rapide en écriture / lecture rapide, moins de mémoire, peut-être un peu unelegant mais fonctionne parfaitement. Aussi longtemps que vous pouvez vous permettre intval(...) sur le lit, bien sûr.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X