2010-07-09 6 views
3

J'ai une boucle do/while qui va au-dessus des lignes de base de données. Parce qu'il s'exécute plusieurs jours au moment de traiter 100000s de lignes, la consommation de mémoire est important de garder le contrôle ou il va planter. À l'heure actuelle, chaque itération ajoute environ 4 Ko à l'utilisation de la mémoire du script. J'utilise memory_get_usage() pour surveiller l'utilisation. Je désinsère toutes les variables utilisées dans la boucle à chaque itération, donc je ne sais vraiment pas ce que je pourrais faire d'autre. Ma conjecture est que do/while rassemble des données à chaque itération et c'est ce qui consomme les 4kb de mémoire. Je sais que 4kb ne sonne pas beaucoup mais il commence bientôt à s'additionner quand vous avez 100000s d'itérations. Quelqu'un peut-il suggérer une autre façon de parcourir une grande quantité de lignes de base de données ou comment éliminer cette "fuite de mémoire"?PHP & do/while fuite de mémoire en boucle

éditer Voici le code de la boucle UPDATED. Au dessus, il n'y a que quelques require_once() s.

$URLs = new URLs_url(db()); 
$c = new Curl; 
$c->headers = 1; 
$c->timeout = 60; 
$c->getinfo = true; 
$c->follow = 0; 
$c->save_cookies = false; 

do { 
    // Get url that hasn't been checked for a week 
    $urls = null; 

    // Check week old 
    $urls = $URLs->all($where)->limit(10); 

    foreach($urls as $url) { 
     #echo date("d/m/Y h:i").' | Checking '.$url->url.' | db http_code: '.$url->http_code; 

     // Get http code  
     $c->url = $url->url; 
     $data = $c->get(); 

     #echo ' - new http_code: '.$data['http_code']; 

     // Save info 
     $url->http_code = $data['http_code']; 
     $url->lastchecked = time(); 
     $URLs->save($url); 
     $url = null; 
     #unset($c); 
     $data = null; 
     #echo "\n".memory_get_usage().' | '; 
     echo "\nInner loop memory usage: ".memory_get_usage(); 
    } 
    echo "\nOuter loop memory usage: ".memory_get_usage(); 

} while($urls); 

Certains journaux comment la consommation de mémoire se comporte dans les deux boucles:

Inner loop memory usage: 611080 
Inner loop memory usage: 612452 
Inner loop memory usage: 613788 
Inner loop memory usage: 615124 
Inner loop memory usage: 616460 
Inner loop memory usage: 617796 
Inner loop memory usage: 619132 
Inner loop memory usage: 620500 
Inner loop memory usage: 621836 
Inner loop memory usage: 623172 
Outer loop memory usage: 545240 
Inner loop memory usage: 630680 
Inner loop memory usage: 632016 
Inner loop memory usage: 633352 
Inner loop memory usage: 634688 
Inner loop memory usage: 636088 
Inner loop memory usage: 637424 
Inner loop memory usage: 638760 
Inner loop memory usage: 640096 
Inner loop memory usage: 641432 
Inner loop memory usage: 642768 
Outer loop memory usage: 556392 
Inner loop memory usage: 640416 
Inner loop memory usage: 641752 
Inner loop memory usage: 643088 
Inner loop memory usage: 644424 
Inner loop memory usage: 645760 
Inner loop memory usage: 647096 
Inner loop memory usage: 648432 
Inner loop memory usage: 649768 
Inner loop memory usage: 651104 
Inner loop memory usage: 652568 
Outer loop memory usage: 567608 
Inner loop memory usage: 645924 
Inner loop memory usage: 647260 
Inner loop memory usage: 648596 
Inner loop memory usage: 649932 
Inner loop memory usage: 651268 
Inner loop memory usage: 652604 
Inner loop memory usage: 653940 
Inner loop memory usage: 655276 
Inner loop memory usage: 656624 
Inner loop memory usage: 657960 
Outer loop memory usage: 578732 
+0

postez aussi votre code. – Sarfraz

+3

Les boucles ne fuient généralement pas la mémoire, les choses dans les boucles le font, nous montrent du code afin que nous puissions aider à diagnostiquer le vrai problème. –

+0

Voici le code. J'espère que cela aide. –

Répondre

2

Ce bit devrait probablement se produire qu'une seule fois, avant que la boucle:

$c = new Curl; 
$c->headers = 1; 
$c->timeout = 60; 
... 
$c->getinfo = true; 
$c->follow = 0; 
$c->save_cookies = false; 

Edit: Oh, la chose entière est enveloppé dans une boucle do/while./Facepalm

Edit 2: Il y a aussi ce bit importante:

unset (class_object de $) ne libère pas ressources allouées par l'objet. Si utilisé dans les boucles, qui créent et détruire des objets, cela pourrait facilement conduire à un problème de ressources. Explicitement, appelez le destructeur pour contourner le problème .

http://www.php.net/manual/en/function.unset.php#98692

Edit 3:

Qu'est-ce que cela? Est-ce que ça ne peut pas être déplacé en dehors de la boucle?

$URLs = new URLs_url(db()); 

Edit 4:

Essayez de supprimer ces lignes, pour l'instant.

$url->http_code = $data['http_code']; 
    $url->lastchecked = time(); 
    $URLs->save($url); 
+0

C'est une boucle do/while. Boucle Foreach est là juste pour les choses en lots. Aussi je ne peux pas vraiment faire Curl avant la boucle parce que chaque itération de foreach vérifie 10 URL différentes. –

+0

@James D52 Mais vous pouvez configurer curl avant et ne pas créer une nouvelle instance à chaque itération. Ces valeurs changent-elles entre itérations?Non, il ne semble pas qu'ils le font. L'URL varie, de même que la réponse de cette URL. Mais, cela n'a pas nécessairement besoin d'une nouvelle instance de boucle pour chaque itération. –

+0

Ok, j'ai déplacé tout le reste au début avant de le faire. Maintenant, il n'y a que $ c-> url = $ url-> url & $ c-> get() dans chaque boucle. N'a pas changé une chose. Je fuis encore ~ ​​1.5kb quelque part:/ –

0

Je pense que votre problème de base est que vous ne les choses de compensation dans la boucle extérieure. Par exemple, il va allouer de la mémoire au tas pour chaque itération de la boucle interne, mais vous n'êtes que unset sur la dernière instance. Je unset tout ce que vous pouvez ($c, $data) à l'fin de la boucle interne.

+0

En mettant des mises à jour à la fin, j'ai réussi à réduire la fuite de mémoire de 4kb à quelque chose comme ~ 1.5kb. Je me demande ce qui fuit encore:/ –

+0

@James pouvez-vous mettre à jour votre question pour correspondre à votre nouveau code? –

+0

@James, déplacez l'appel à 'memory_get_usage()' pour être après 'unset ($ URLs)', j'ai l'impression que vous trouverez que la croissance de 1.5kb est liée aux '$ URLs-> save()' appel. –

0

Le problème est probablement

$c = new Curl 

Est-il possible d'instancier Curl une fois en dehors de la boucle, puis garder à l'intérieur de réutiliser la même instance. Vous pouvez réinitialiser tous les champs à null dans la boucle si vous le souhaitez.

J'ai eu un problème similaire. Unset n'a pas fonctionné - il s'est avéré que la collecte des ordures était des ordures. Quand j'ai réutilisé des objets, ça s'est bien passé (eh bien, ça s'est cassé pour des raisons différentes, donc j'ai fini par réimplémenter en Java).

+1

@Michale Jones Voir ce commentaire à propos de unset() dans le manuel de PHP: http://www.php.net/manual/fr/function.unset.php#98692 –

+0

@George Marian: Merci. Je ne le savais pas. –

0

Cela peut ou peut ne pas vous aider, mais en 2000, j'avais un client qui avait très lent internet et voulait faire toutes les mises à jour de son site web cms et mettre à jour pour vivre une fois terminé. À l'époque sur IIS sur win xp, je ne pouvais pas trouver un moyen d'augmenter le délai de script de 60 secondes, et aurait généralement besoin de 2 bonnes minutes pour faire la mise à jour, donc il serait évidemment temps. Pour résoudre ce problème, je voudrais que le script mette à jour un certain nombre de lignes dont l'exécution en toute sécurité a été garantie en moins d'une minute, puis appelez-vous avec un paramètre d'où continuer, et ainsi de suite jusqu'à ce que toutes les lignes soient mises à jour . Peut-être que vous pourriez essayer quelque chose de similaire pour votre situation? Peut-être l'exécuter pendant un certain laps de temps avant de s'appeler, ou dans votre cas, peut-être vérifier la mémoire, et rediriger lorsque l'utilisation devient trop élevée?

J'utilise quelque chose comme ceci:

Haut de script:

$started = microtime(true); 

Ensuite, dans votre boucle:

if((microtime(true)-$started) > ($seconds_to_redirect)) { 
    //call script with parameter 
} 

C'est tout ce que je peux penser.