41 votes

Augmentation de la limite de mémoire de PHP. À quel moment cela devient-il insensé ?

Dans un système sur lequel je travaille actuellement, il y a un processus qui charge une grande quantité de données dans un tableau pour les trier, les agréger ou autre. Je sais que ce processus doit être optimisé pour l'utilisation de la mémoire, mais à court terme, il doit simplement fonctionner.

Compte tenu de la quantité de données chargées dans le tableau, nous nous heurtons sans cesse à la limite de la mémoire. Elle a été augmentée plusieurs fois, et je me demande s'il y a un moment où l'augmenter devient généralement une mauvaise idée ou est-ce que uniquement une question de quantité de RAM sur la machine ?

La machine dispose de 2 Go de RAM et la limite de mémoire est actuellement fixée à 1,5 Go. Nous pouvons facilement ajouter plus de RAM à la machine (et nous le ferons de toute façon).

D'autres personnes ont-elles rencontré ce genre de problème ? et quelles ont été les solutions ?

6 votes

Honnêtement, vous ne devriez pas vous préoccuper de fixer une limite de mémoire, mais plutôt de déterminer où se trouve votre fuite de mémoire et de la réparer. Ce n'est pas une solution de simplement augmenter la limite de mémoire, c'est éviter un problème dans le code. Examinez les objets pour lesquels vous définissez et supprimez des valeurs afin d'éliminer une fuite.

0 votes

Pouvez-vous être précis quant à la quantité de données ? Qu'entendez-vous par grande quantité ?

8 votes

@Frederico : L'OP n'essaie pas de réparer une fuite de mémoire, il demande une solution pour gérer de très grands ensembles de données en PHP.

59voto

Pascal MARTIN Points 195780

La configuration de l memory_limit de PHP s'exécutant en tant que module Apache pour le serveur de pages web doit prendre en compte le nombre de processus Apache que vous pouvez avoir en même temps sur la machine -- voir la page MaxClients option de configuration pour Apache.

Si MaxClients est de 100 et que vous disposez de 2 000 Mo de RAM, un calcul très rapide montrera que vous ne devez pas utiliser plus de 20 Mo *(car 20 Mo * 100 clients = 2 Go de RAM, c'est-à-dire la quantité totale de mémoire dont dispose votre serveur)* pour la valeur de memory_limit.

Et ceci sans tenir compte du fait qu'il y a probablement d'autres choses qui fonctionnent sur le même serveur, comme MySQL, le système lui-même, ... Et qu'Apache utilise probablement déjà de la mémoire pour lui-même.

Bien sûr, il s'agit également d'un "scénario du pire", qui considère que chaque page PHP utilise la quantité maximale de mémoire qu'elle peut.

Dans votre cas, si vous avez besoin d'une si grande quantité de mémoire pour une seule tâche, je n'augmenterais pas la valeur de l'espace mémoire de l'ordinateur. memory_limit pour PHP fonctionnant comme un module Apache.

Au lieu de cela, je lancerais ce travail à partir de la ligne de commande (ou via une tâche cron) et spécifier une valeur plus élevée memory_limit spécifiquement dans ce seul et unique cas.

Cela peut être fait avec le -d de php, comme :

$ php -d memory_limit=1GB temp.php
string(3) "1GB"

Considérant, dans ce cas, que temp.php ne contient que :

var_dump(ini_get('memory_limit'));

À mon avis, c'est beaucoup plus sûr que d'augmenter la limite de mémoire du module PHP d'Apache - et c'est ce que je fais habituellement lorsque j'ai un grand ensemble de données, ou des données vraiment lourdes que je ne peux pas optimiser ou paginer.

Si vous devez définir plusieurs valeurs pour l'exécution du CLI PHP, vous pouvez également lui demander d'utiliser un autre fichier de configuration, au lieu du php.ini par défaut, avec l'option -c option :

php -c /etc/phpcli.ini temp.php

De cette façon, vous avez :

  • /etc/php.ini pour Apache, avec de faibles memory_limit , faible max_execution_time , ...
  • et /etc/phpcli.ini pour les lots exécutés en ligne de commande, avec pratiquement aucune limite

Cela garantit que vos lots pourront être exécutés - et que vous aurez toujours la sécurité pour votre site web ( memory_limit et max_execution_time étant des mesures de sécurité)

Néanmoins, si vous avez le temps d'optimiser votre script, vous devriez le faire ; par exemple, dans ce genre de situation où vous devez traiter beaucoup de données, la pagination est indispensable ;-)

0 votes

Oui, la limite n'est augmentée que pour le processus qui l'exige. Malheureusement, la pagination n'est d'aucune utilité dans ce cas ; le résultat final n'est qu'une poignée (une vingtaine) de chiffres statistiques, c'est le traitement qui nécessite de l'espace.

0 votes

Oh, OK... Alors, je suppose que cela dépend de la quantité de mémoire "libre" dont vous disposez au moment de lancer ce processus : si vous le lancez au milieu de la nuit, quand il n'y a presque personne qui utilise votre serveur, peut-être que 1.5 GB pourrait être OK (j'utiliserais plus, pour laisser de la mémoire au reste du système) -- mais vous seul pouvez dire combien votre serveur est chargé à ce moment-là.

4 votes

Dans certaines versions de PHP (par exemple, PHP 5.3.15 avec Suhosin-Patch), le paramètre est 1G, et non 1GB. Testez-le ou PHP fixera la limite à la valeur la plus basse et votre script ne s'exécutera pas, par exemple en utilisant php -d memory_limit=1G -r "echo ini_get('memory_limit');"

2voto

arul Points 10719

Avez-vous essayé de diviser l'ensemble de données en plusieurs parties et de ne traiter qu'une partie à la fois ?

Si vous récupérez les données à partir d'un fichier disque, vous pouvez utiliser la fonction fread() pour charger de plus petits morceaux, ou une fonction une sorte de requête de base de données sans tampon en cas de base de données.

Je n'ai pas vérifié PHP depuis la version 3.quelque chose, mais vous pourriez aussi utiliser une forme de cloud computing. Un jeu de données de 1 Go semble être assez gros pour être traité sur plusieurs machines.

0 votes

L'idée est de ne lire les données qu'en fonction des besoins (comme vous le suggérez avec fread()), mais c'est le remaniement que nous n'avons pas encore effectué.

0 votes

C'est la réponse correcte, IMNSHO : à moins que le jeu de données ne soit entièrement corrélé, il est généralement possible de traiter une partie à la fois, et il est rarement nécessaire de tout garder en mémoire. Comme l'indique le PO, cela nécessite souvent un remaniement non trivial.

1voto

zombat Points 46702

Étant donné que vous savez qu'il y a des problèmes de mémoire avec votre script qui doivent être corrigés et que vous ne cherchez que des solutions à court terme, alors je n'aborderai pas les moyens de aller sur le profilage et de résoudre vos problèmes de mémoire. On dirait que vous allez y arriver.

Donc, je dirais que les principales choses que vous devez garder à l'esprit sont :

  • Charge mémoire totale du système
  • Capacités du système d'exploitation

Le PHP n'est qu'un petit composant du système. Si vous lui permettez de consommer une grande quantité de votre RAM, alors les autres processus en souffriront, ce qui pourrait à son tour affecter le script lui-même. Notamment, si vous extrayez beaucoup de données d'une base de données, votre SGBD peut avoir besoin de beaucoup de mémoire pour créer des ensembles de résultats pour vos requêtes. Comme solution rapide, vous pouvez identifier toutes les requêtes que vous exécutez et libérer les résultats dès que possible afin de vous donner plus de mémoire pour un travail de longue durée.

En termes de capacités du système d'exploitation, vous devez garder à l'esprit que les systèmes 32 bits, sur lesquels vous travaillez probablement, ne peuvent adresser que jusqu'à 4 Go de RAM sans manipulation spéciale. Souvent, la limite peut être bien inférieure en fonction de l'utilisation qui en est faite. Certains chipsets et configurations de Windows peuvent en fait avoir moins de 3 Go disponibles pour le système, même si 4 Go ou plus sont physiquement installés. Vous devez vérifier la capacité de votre système.

Vous dites que vous avez augmenté la limite de mémoire plusieurs fois, donc manifestement ce travail prend de plus en plus d'ampleur. Si vous en êtes à 1,5 Go, même l'installation de 2 Go de RAM supplémentaires ne sera qu'un bref sursis.

D'autres personnes ont-elles rencontré ce genre de problème ? et quelles ont été les solutions ?

Je pense que vous savez probablement déjà que la seule vraie solution est de décomposer et de passer le temps d'optimiser le script rapidement, ou vous vous retrouverez avec un travail qui sera trop gros pour être exécuté.

0 votes

La machine est essentiellement dédiée à PHP, les serveurs de base de données sont séparés. Les augmentations précédentes de la limite n'étaient pas dues au fait que le travail augmente (bien que ce soit le cas, mais pas si rapidement), elles étaient insuffisantes pour "régler" le problème (nous avons donc essayé une limite plus importante). Nous avons maintenant une limite qui permet au processus de fonctionner, mais ce n'est certainement qu'une solution à court terme. Bon point sur les limitations du système, c'est une machine 64 bits et nous allons augmenter la RAM de toute façon. Quoi qu'il en soit, je pense que vous avez apaisé mes craintes que jeter autant de mémoire sur un seul processus était absurde. Les SGBDR le font, pourquoi pas moi :)

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