67 votes

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

Depuis ma question est de plus en plus longues et de plus, je décide de ré-écrire toute la question pour l'améliorer et le rendre plus court.

Je lance mon site internet sur serveur dédié avec 8 go de mémoire. Je suis pleinement conscient que je dois augmenter la limite de mémoire php.paramètre ini. J'ai mis de 128M de 256M et à -1. Toujours le problème de la persistance.

Fatal error: Out of memory (alloués 786432) (tried to allocate 24576 octets) D:\www\football\views\main.php sur la ligne 81

La mémoire n'a pas de sens car il dit seulement 786432 octets est alloué et il fallait 24576 octets de plus.

786432 octets est seulement 768 kilo-octets et est assez petit.

Conseils

  • L'erreur se produit sur une ligne aléatoire. Il n'est pas toujours l'erreur sur la ligne numéro 81.
  • À l'heure de pointe, Apache prend seulement environ 500 mo de mémoire. J'ai encore 6 GO de rechange.
  • Il n'y a pas de boucle infinie.
  • Le script prend 1,042,424 octets. L'obtention de ce numéro, echo memory_get_peak_usage();
  • Le jeu de résultats de MySQL est faible (au plus 12 de lignes, purement texte, pas de données blob)
  • (Important) Si je redémarre Apache une fois tous les deux jours, l'erreur a disparu. Il se produit généralement lors de l'exécution d'Apache plus de 2 jours.
  • J'ai inclus le profilage le script et vous pouvez l'obtenir ici.
  • Ce serveur dédié est purement utilisée pour exécuter un seul site web. Ce site est un haut trafic de site web avec une moyenne de 1000 visiteurs chaque minute. À l'heure de pointe, il y aura de 1 700 à 2 000 visiteurs d'accéder en même temps.

Serveur Spec

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

Solution

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

  1. favicon.ico était manquant, qui mess avec mon trajet moteur. Bien que mon trajet moteur est très faible, mais en y favicon.ico, elle permet de réduire l'utilisation de la mémoire en n'exécutant pas de route à moteur. La plupart de la partie de mon site web a, et j'ai oublié de le mettre pour cette nouvelle section.
  2. Limiter MaxRequestPerChild aide. Dans mon autre serveur dédié, j'ai mon MaxRequestPerChild limitée. Pour ce serveur, je l'ai mis à 0. J'ai toujours pensé que chaque script est isolé. Disons que si mon script prend 800ko à exécuter. Dès son achèvement, Apache ou de PHP doit gratuit de 800 ko de mémoire. Il semble qu'il ne fonctionne pas de cette façon. Limited MaxRequestPerChild aide à prévenir la fuite de mémoire par la création de nouveaux processus après limited MaxRequestPerChild et l'ancien processus est en train de mourir. C'est mon nouveau réglage.

    ThreadsPerChild      1500
    MaxRequestsPerChild  10000 
    
  3. ob_flush(); fait de réduire un peu plus de mémoire. Il n'aide pas beaucoup, mais tous les bits de l'optimisation de l'aide.

  4. Je l'ai utilisé, xdebug que je n'ai jamais utilisé avant comme suggéré par des gens qui tentent de répondre à cette question. Je dois dire que c'est l'outil idéal et j'ai optimisé un peu fourre pour le faire courir un peu plus vite.
  5. J'ai désactiver un peu inutile module Apache. Je suis en train de le désactiver un par un et de le laisser quelques jours de test pour s'assurer qu'il fonctionne parfaitement avant que je désactiver un autre. J'ai tous inutiles extension PHP désactiver maintenant.
  6. La plupart de mes script dans ce serveur utilisé de façon traditionnelle (pas de modèle, pas de couche de base de données, pur PHP, HTML, et l'héritage mysql_* fonction). Pour être honnête, il est très rapide et extrêmement petite mémoire. Toutefois, l'entretien, le script n'est pas très facile car le site est de plus en plus longues. J'ai essayé de convertir certaines parties du site dans un cadre approprié (mon petit cadre). La raison que j'ai utilisé mon propre cadre de référence, car il est tout petit (3 ko pour l'ensemble du cadre et ne comprennent que ce dont j'ai besoin).
  7. Commutation de IIS7.5 la résolution de ce problème complètement.

30voto

greg Points 1312

Je suis tombé sur le même genre de problème avec le serveur de mourir lors de l'utilisation de la swap. C'est parce que mod_php ne libère pas la mémoire jamais. Donc, processus Apache continuer de croître, soit en arrivant à apache ou de PHP limite de mémoire ou, si il n'y a pas de limite, le plantage du serveur.

Le redémarrage d'apache rend pour frayer de nouvelles fraîches slim processus, mais l'exécution des scripts PHP au fil du temps, ils grandissent jusqu'à ce que les problèmes surviennent.

La solution est de faire de apache tuer les processus après un certain nombre de requêtes servies donc, il va en créer de nouvelles ( Il y a quelques questions à ce sujet) la réduction de la MaxRequestsPerChild option de configuration, disons, 100 (valeur par Défaut: 1000).

Bien sûr, cela peut réduire le serveur de performances car il faut des ressources pour tuer et spaws de nouveaux processus, mais au moins il garde le site de travail. Vous pourriez être tenté d'augmenter le nombre de processus en cours d'exécution pour garder des performances de haut, assurez-vous (PHP ou apache) limite de mémoire max x nombre de procédés de ne pas obtenir plus de votre serveur de ram physique.

Voici mon expérience, j'espère que ça aide.

15voto

Mike Mackintosh Points 7465

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

memory_get_usage sera de retour l'actif de la quantité de mémoire qui est allouée lorsqu'il est appelé.

ini_set('memory_limit', '256M'); permettra de définir l'allocation maximale de PHP empreinte sur vos systèmes de Mémoire. Si vous obtenez OOM à 768K, upping il ne résoudra pas le problème.

Il n'y a aucune indication quant à ce que la version de PHP que vous utilisez, mais je voudrais suggérer une mise à jour immédiatement. Il y a plusieurs bugs où Zend Gestionnaire de Mémoire ne désalloue la mémoire, ce qui vous ferait exactement le même problème.

Sont à la fois votre serveur local et le serveur de production exécuter la même version de système d'exploitation, la même longueur de bits et la même version de PHP? La réponse sera "non".

Si c'est sans rapport avec les fenêtres malloc() question, c'est un sous domaine et probablement dans un VirtualHost, et en allouant seulement 768k, ça ressemble presque à un OS en question.

Exécutez tasklist à partir de l'invite de commande lorsque vous accédez à votre script. Voyez-vous un supplément de Apache thread, ou de l'utilisation de la Mémoire à travers le processus de spike?

Une dernière idée est, exécutez flush() et/ou ob_flush(); après chaque tour de boucle pour la table de la ligne/colonne. Ceci devrait effacer de votre mémoire tampon et vous faire économiser un peu de mémoire dans l'événement c'est là que le problème se produit.

8voto

maxwell2022 Points 485

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

6voto

Carmageddon Points 89

Installez xdebug et activez le déclencheur du profileur. Générez un fichier de profil, 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!

4voto

Xeoncross Points 13263

Je suppose que vous n'avez pas modifié le droit de l' php.ini ou que vous n'avez pas redémarré PHP et/ou le serveur web.

Créer un phpinfo.php page dans votre docroot avec le contenu de l' <?php phpinfo(); afin de vous assurer de changer la corriger php.ini. En plus de l'emplacement de l' php.ini le fichier, le serveur web est à l'aide, il sera également le maximum de mémoire de script permis.

Ensuite, je voudrais ajouter quelques traces de pile à votre page de sorte que vous pouvez voir la chaîne des événements qui ont conduit à cela. La fonction suivante va attraper les erreurs fatales et de fournir 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é lent ol' Apache.

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