web-dev-qa-db-fra.com

Erreur fatale: mémoire insuffisante, mais j'ai beaucoup de mémoire (PHP)

Comme ma question est de plus en plus longue, je décide de réécrire toute la question pour la rendre meilleure et plus courte.

Je dirige mon site Web sur un serveur dédié avec 8 Go de mémoire. Je suis tout à fait conscient que je dois augmenter la limite de mémoire sur le paramètre php.ini. Je l'ai réglé de 128M à 256M et à -1. Le problème reste la persistance.

Erreur fatale: Mémoire insuffisante (786432 affecté) (tentative d'allocation de 24576 Octets) dans D:\www\football\views\main.php à la ligne 81

Le manque de mémoire n'a pas de sens car il est dit que seuls 786432 octets sont alloués et qu'il en faut plus de 24576 octets.

786432 octets ne font que 768 kilo-octets et sont assez petits.

Astuces

  • L'erreur se produit sur une ligne très aléatoire. La ligne 81 n’est pas toujours erronée.
  • Aux heures de pointe, Apache ne prend que 500 Mo de mémoire environ. J'ai encore 6 Go à épargner.
  • Il n'y a pas de boucle infinie.
  • Le script prend 1 042 424 octets. Obtenir ce numéro de echo memory_get_peak_usage();
  • Le résultat de MySQL est petit (au plus 12 lignes, purement texte, pas de données blob)
  • (Important) Si je redémarre Apache une fois tous les deux jours, l'erreur disparaît. Cela se produit généralement lorsque Apache s'exécute plus de 2 jours.
  • J'ai inclus le profilage du script et vous pouvez l'obtenir ici .
  • Ce serveur dédié est purement utilisé pour exécuter un seul site Web. Ce site Web est un site à fort trafic de 1 000 visiteurs par minute en moyenne. Aux heures de pointe, 1 700 à 2 000 visiteurs accèderont en même temps.

Spécification du serveur

Système d'exploitation: Windows 2008 R2 64 bits
CPU: Intel Core i5 - 4 cœurs
RAM: 8 Go
Apache 2.2
PHP 5.3.1
Stockage: 2 x 1 TB disques durs
Bande passante: 10 TB par mois

Solution

J'ai enfin réglé et corrigé le problème et je voudrais partager ici ce que j'ai fait pour l'améliorer:

  1. favicon.ico manquait quel gâchis avec mon moteur de route. Bien que mon moteur de routage soit très petit, mais en incluant favicon.ico, il permet de réduire l'utilisation de la mémoire en n'exécutant pas mon moteur de routage. La majeure partie de mon site l’a et j’ai oublié de le mettre pour cette nouvelle section.
  2. Limiter MaxRequestPerChild aide. Sur mon autre serveur dédié, ma MaxRequestPerChild est limitée. Pour ce serveur, je l'ai mis à 0. J'ai toujours pensé que chaque script était isolé. Disons que si mon script prend 800 Ko à exécuter. Une fois terminé, Apache ou PHP devrait libérer 800 Ko de mémoire. Il semble que cela ne fonctionne pas de cette façon. Limited MaxRequestPerChild aide à prévenir les fuites de mémoire en créant un nouveau processus après MaxRequestPerChild limité et que l'ancien processus est en train de mourir. Ceci est mon nouveau paramètre.

    ThreadsPerChild      1500
    MaxRequestsPerChild  10000 
    
  3. ob_flush(); réduit légèrement plus la mémoire. Cela n’aide pas beaucoup mais chaque optimisation est utile.

  4. J'ai utilisé xdebug que je n'ai jamais utilisé auparavant, comme suggéré par des personnes qui tentent de répondre à cette question. Je dois dire que c’est un excellent outil et j’ai optimisé quelques éléments pour le rendre légèrement plus rapide.
  5. J'ai désactivé quelques modules Apache inutiles. J'essaie de le désactiver un par un et de le laisser quelques jours pour vérifier qu'il fonctionne parfaitement avant d'en désactiver un autre. J'ai toutes les extensions inutiles PHP désactivées maintenant.
  6. La plupart de mes scripts sur ce serveur utilisaient la méthode traditionnelle (pas de modèle, pas de couche de base de données, PHP pur, HTML et la fonction héritée mysql_ *). Pour être honnête, il fonctionne très vite et utilise une mémoire extrêmement petite. Cependant, la maintenance du script n’est pas très facile car le site Web est de plus en plus long. J'ai essayé de convertir certaines parties du site Web en un cadre approprié (mon propre cadre minuscule). La raison pour laquelle j'ai utilisé mon propre framework parce qu'il est minuscule (3 Ko pour tout le framework et n'inclut que ce dont j'ai besoin).
  7. Passage à IIS7.5 résoudre ce problème complètement.
58
invisal

J'ai rencontré le même genre de problème avec le serveur en train de mourir en essayant d'utiliser le swap. En effet, mod_php ne libère jamais la mémoire. Ainsi, les processus Apache ne cessent de croître, atteignant soit la limite de mémoire d'Apache ou de PHP, soit, s'il n'y en a pas, un crash du serveur. 

Le redémarrage d'Apache permet de créer de nouveaux processus minces, mais à mesure qu'ils exécutent des scripts PHP au fil du temps, ils se développent jusqu'à ce que des problèmes se posent. 

La solution consiste à obliger Apache à supprimer les processus après un certain nombre de requêtes afin qu’il en crée de nouvelles (il y a quelques questions liées à cela ) réduisant l’option MaxRequestsPerChild configuration à, disons 100 ( La valeur par défaut est 1000). 

Bien sûr, cela peut réduire les performances du serveur car il faut des ressources pour tuer et générer de nouveaux processus, mais au moins, le site continue de fonctionner. Vous pourriez être tenté d'augmenter le nombre de processus en cours pour maintenir des performances élevées. Assurez-vous que la limite de mémoire PHP (ou Apache) x nombre maximal de processus ne dépasse pas la mémoire physique de votre serveur.

Voici mon expérience, espérons que cela aide.

25
greg

Pour commencer, memory_get_peak_usage() ne sera pas utile ici. Il ne retournera que la quantité de mémoire allouée, et c'est le même nombre qui a causé l'erreur.

memory_get_usage renverra la quantité de mémoire active allouée lors de son appel. 

ini_set('memory_limit', '256M'); définira l’allocation maximale de l’empreinte PHP sur la mémoire de votre système. Si vous obtenez le MOO à 768K, le fait d’augmenter ne résoudra pas le problème. 

Il n'y a aucune indication sur la version de PHP que vous utilisez, mais je suggérerais une mise à niveau immédiatement. Il y a plusieurs bogues où le gestionnaire de mémoire de Zend ne parvient pas à libérer de la mémoire, ce qui vous mènerait exactement au même problème.

Votre serveur local et votre serveur de production utilisent-ils la même version du système d'exploitation, le même bit long et la même version de PHP? La réponse sera non.

S'il n'est pas lié au problème windows malloc(), étant un sous-domaine et probablement au sein d'un VirtualHost et n'attribuant que 768 Ko, cela ressemble presque à un problème de système d'exploitation.

Exécutez tasklist à partir de la commande Invite lorsque vous accédez à votre script. Voyez-vous un thread Apache supplémentaire ou une utilisation de la mémoire au cours de la hausse des processus?

Une dernière idée est, exécutez flush() et/ou ob_flush(); après chaque boucle pour la ligne/colonne du tableau. Cela devrait effacer votre mémoire tampon et vous faire économiser de la mémoire au cas où le problème se produirait.

14
Mike Mackintosh

Je commencerais par mettre à niveau PHP vers la version 5.4+, car certaines applications sont jusqu'à 50% plus rapides . Ils ont corrigé un grand nombre de fuites de mémoire. Veuillez voir becnhamrks: http://news.php.net/php.internals/57760

8
maxwell2022

Installez xdebug et activez le déclencheur du profileur . Générez un fichier de profileur, puis publiez le fichier cachegrind si vous ne pouvez toujours pas identifier la source du problème.

EDIT: fichier de profileur de la page où la fuite de mémoire se produit bien sûr!

6
Carmageddon

Veuillez noter que l'erreur est Out of memory et n'est pas Allowed memory size [..] exhausted.

Donc, la fuite de mémoire est ailleurs sur le système. Il est possible que le serveur mysql utilise beaucoup de mémoire système après cette requête lourde, laissant Apache/php sans lui et sans swap physique.

Cela devrait expliquer l'erreur toujours sur la même ligne (et/ou dans le même script).

5
Luca Rainone

Je suppose que vous n’avez pas édité le bon php.ini ou n’avez pas redémarré PHP et/ou le serveur Web.

Créez une page phpinfo.php dans votre docroot avec le contenu <?php phpinfo(); pour vous assurer que vous modifiez le php.ini correct. Outre l'emplacement du fichier php.ini utilisé par le serveur Web, il indique également la mémoire de script maximale autorisée.

Ensuite, j'ajouterais quelques traces de pile à votre page afin que vous puissiez voir la chaîne d'événements qui ont conduit à cela. La fonction suivante détectera les erreurs fatales et fournira plus d'informations sur ce qui s'est passé.

register_shutdown_function(function()
{
    if($error = error_get_last())
    {
        // Should actually log this instead of printing out...
        var_dump($error);
        var_dump(debug_backtrace());
    }
});

Personnellement, Nginx + PHP-FPM est ce que j’ai utilisé pendant des années, depuis que j’ai quitté le lent Apache.

4
Xeoncross

Hey, j'ai aussi le même problème sur mon serveur. Je viens de changer les choses suivantes:

remplacez php.ini par ...

memory_limit = 128M

et ajouter à httpd.conf

RLimitMEM 1073741824 2147483648

et redémarrez Apache et j'ai supprimé l'erreur: 

3
Rohitashv Singhal

Peut-être un problème avec MySQL et le nombre de connexions ouvertes, d’où sa résolution lors du redémarrage tous les quelques jours. Est-ce qu'ils se ferment automatiquement à la fermeture du script?

3
Matt Humphrey

Juste pour récapituler (j'ajoute cette réponse assez loin de la question initiale):

  • PHP est incapable d'allouer ce qui semble être une petite quantité de mémoire
  • l'utilisation actuelle de la mémoire au moment où l'erreur se produit + la quantité demandée est inférieure à la limite de mémoire actuellement en vigueur
  • le système a 6 Go disponibles pour utilisation par PHP lorsque cela se produit
  • puisque le problème est résolu en redémarrant Apache - c'est Apache qui empêche la mémoire de beig disponible pour PHP

Si tout cela est valable, alors la seule explication possible est que le 6Gb est très fragmenté - ce qui me semble un peu improbable. Vous n'avez pas dit comment PHP est appelé depuis Apache - mod_php? fpm? Fcgi?

Je commencerais par examiner chacun des prédicats ci-dessus, en particulier celui de la mémoire libre. Comment savez-vous qu'il y a 6 Go libre lorsque l'erreur se produit ? Une cause plus probable est qu'il se produit une fuite de mémoire que vous ne détectez pas.

Vous n'avez fourni aucun détail sur la configuration d'Apache. Je voudrais aussi voir comment réduire MaxRequestsPerChild et MaxMemFree. (Je ne connais pas très bien Apache, où cela s'appliquera par thread - vous avez vraiment besoin d'une limite par processus). Si vous fournissiez le paramètre de base de la configuration Apache, nous pourrions peut-être faire d'autres suggestions.

Sauf si vous utilisez abondamment Ajax, assurez-vous que votre durée de conservation est de 2 ou moins.

2
symcbean

cela m'est arrivé il y a quelques jours. J'ai fait une nouvelle installation et c'est toujours arrivé. autant que tout le monde voit et basé sur les spécifications de votre serveur. le plus probable est une boucle infinie. il pourrait ne pas s'agir du code PHP lui-même, mais des requêtes adressées à Apache.

disons que lorsque vous accédez à cette URL http: // localhost/mysite/page_with_multiple_requests

Consultez le journal des accès de votre Apache s'il reçoit plusieurs demandes. retracez cette demande et extrayez le code qui pourrait causer un «goulot d'étranglement» au système (exec () lorsque j'utilise sendmail). Le goulot d'étranglement dont je parle n'a pas besoin d'être une "boucle infinie". Ce pourrait être une fonction qui prend un certain temps à terminer. ou peut-être quelques unes des ' fonctions d'exécution du programme ' de php

Vous devrez peut-être aussi vérifier les requêtes ajax (celles qui sont exécutées lors du chargement de la page). si cette demande ajax redirige vers la même URL 

par exemple. httpx: // localhost/mysite/page_with_multiple_requests

il serait 'refaire' les demandes encore une fois

cela aiderait si vous postez les lignes aléatoires ou le code lui-même où le script se termine, peut-être y at-il un code "en boucle" quelque part. imho php n'appelle pas que des lignes aléatoires pour rien.

http://blog.piratelufi.com/2012/08/browser-sending-multiple-requests-at-once/

1
kapitanluffy

J'ai eu un problème similaire avec PHP:

1) Vérifiez vos journaux d'erreur. Éliminez TOUTES les erreurs avant de continuer . 2) Envisagez de modifier votre configuration Apache pour éliminer les modules inutilisés - ceci réduira l'empreinte nécessaire à PHP - voici un excellent lien pour cela - il est spécifique à Wordpress mais devrait être très utile http://thethemefoundry.com/blog/optimize-Apache-wordpress/

Pour vous donner une idée du type de bogue que j'ai trouvé, j'avais un code qui essayait de poster du contenu sur Facebook, Facebook a ensuite modifié leur API, donc ça a cassé, j'ai aussi utilisé un 'expirateur de contenu', ce qui signifiait essentiellement qu'il réessayait. pour publier ce contenu sur Facebook en laissant des charges d'objets en mémoire.

1
Dave Hilditch

Essayez d’exécuter php sur fcgid, cela peut aider:

Ce sont les erreurs classiques que vous verrez lors de l’exécution de PHP en tant que Module Apache. Nous avons lutté avec ces erreurs pendant des mois. Passer à utiliser PHP via mod_fcgid (comme le recommande James) résoudra tous ces problèmes problèmes. Assurez-vous de disposer de la dernière version redistribuable de Visual C++ paquet installé: 

http://support.Microsoft.com/kb/2019667

Je vous recommande également de passer à la version 64 bits de MySQL. Pas de réel raison pour exécuter la version 32 bits plus.

Source: Apache 2.4.6.0 crash en raison d'un problème dans php5ts.dll 5.5.1.0

1
Igory

Erreur fatale: mémoire insuffisante (affectée dans RESOLU
J'ai eu le même problème, pendant des mois, pas de solution. Enfin, j’étais en train de vérifier l’un des dossiers Apache i.e (\ Apache\conf\extra), j’ai rencontré ce fichier qui contrôle l’allocation de mémoire d’Apache. le nom du fichier est httpd-mpm , dans ce fichier, vous devez augmenter la valeur MaxMFree, qui est définie pour 2048, quelque chose de plus élevé. IfModule mpm_netware_module.

Ceux-ci ont résolu mon problème. J'espère que ça aide 

1
Bilyaminu K

Dans le fichier de sortie du profileur, j'ai remarqué deux choses que je n'aimais pas beaucoup/dans lesquelles je ne faisais pas beaucoup confiance et que je voudrais examiner:

Mis à part le fait de ne pas connaître la signification des nombres en sortie pour détecter une anomalie ou le fonctionnement des scripts PHP ..., n'est-ce pas un problème? Avoir une inclusion dans le même fichier main.ph, qui ressemble à une chose récursive?

2121 fl=D:\www\football\views\main.php
2122 fn=include::D:\www\football\views\main.php

Remarqué que le fichier D:\www\football\views\main.php utilise plusieurs fois des fonctions de chaîne, je suppose qu'il appelle ces fonctions sur les données renvoyées par votre requête:

strlen
substr
strtotime

Si, comme dans le langage C, ces fonctions requièrent des chaînes null terminées ou une autre terminaison de chaîne pour éviter les problèmes de mémoire, je regarderais les chaînes renvoyées par votre requête. 

Pouvez-vous poster l'URL de votre site web?

1
Only You

La plupart du temps, vous obtenez une telle erreur, le problème est dans le code. Je n'essaie pas de dire que vous écrivez du code qui est mauvais, j'essaie de dire que vous devez observer attentivement ce qu'il y a dans l'utilisation de cette quantité de mémoire.

Rappelez-vous toujours que " La récupération de place dans PHP est assez mauvaise ", ce n'est pas comme Java, aucun autre langage de ce type. il existe un moyen d'appliquer la récupération de place via gc_collect_cycle , mais, à mon avis, cela ne résoudra pas votre problème . PHP libère toute la mémoire utilisée pour l'exécution d'une page, une fois le cycle requête-réponse terminé vous risquez donc d’être confronté à des problèmes de mémoire si votre script est long, comme un script en arrière-plan (Gearman, etc.), car la mémoire n’est pas libérée tant que le script n’a pas été exécuté.

Si ce qui précède n'est pas le cas avec votre scr, pt, et comme vous l'avez dit, aucun code ne nécessite une telle quantité de mémoire, alors le problème est très certainement dans le code lui-même et la mise à niveau vers n'importe quelle version de PHP ne résoudra pas le problème. Une fois, j’étais confronté à un de mes scripts Gearman et un problème lié à l’une de mes boucles, j’ajoutais une variable à un de mes tableaux, était très lourd (environ 110 Ko de données). Je suggère donc de faire une inspection minutieuse de votre code.

Ravir 

1
Ravish

Il s'agit d'un bogue connu dans PHP v 5.2 pour Windows, il est présent au moins jusqu'à la version 5.2.3: https://bugs.php.net/bug.php?id=41615

Aucune des corrections suggérées ne nous a aidé, nous allons devoir mettre à jour PHP.

1
Anonymous User

Les deux faits suivants indiquent clairement des fuites de mémoire:

  1. L'erreur apparaît à différentes lignes de votre code,
  2. L'erreur indique une allocation de mémoire relativement petite.

Je choisirais d'abord PDO, en désactivant toutes les autres extensions et en le laissant fonctionner du jour au lendemain en utilisant quelque chose comme Siege/Apache Bench (ab). Vous pouvez également essayer de l'exécuter en utilisant l'interface cli (assurez-vous simplement de conserver les mêmes limites de mémoire).

Vous pouvez utiliser la fonction memory_get_peak_usage() à la fin de votre script pour voir la quantité de mémoire utilisée par PHP.

D'après votre commentaire, 800 Ko, ce qui est correct; certainement pas la quantité de mémoire gigantesque qui causerait un manque de mémoire ;-)

Enfin, bien que je ne recommande pas la mise à niveau vers la version 5.4 pour le moment, la mise à niveau vers la dernière version de la version 5.3.x en vaut probablement la peine en raison des multiples vulnérabilités et fuites corrigées depuis la version 5.3.1

1
Ja͢ck

Je dirais que le serveur manque de mémoire physique/d'échange, donc PHP ne peut pas allouer suffisamment de mémoire.

Pouvez-vous coller la sortie de free ici?

0
Edson Medina

Pour mon cas, cette erreur a été déclenchée à cause d'une requête select énorme (des centaines de milliers de résultats renvoyés). 

Elle est apparue immédiatement après l’ajout de millions d’enregistrements dans ma base de données pour tester l’évolutivité de WordPress. C’était donc la seule raison probable pour moi.

0
AFA Med