2010-08-01 4 views
7

J'ai la fonction ci-dessous que j'appelle très fréquemment dans une boucle.PHP Garbage collection est nul ou est-ce juste moi?

J'ai attendu 5 minutes que la mémoire a grimpé de 1 Mo à 156 Mo. Est-ce que le collabateur de garabage de PHP doit se présenter et réduire cela à un moment donné ?!

Est-ce parce que j'ai défini la limite de mémoire à 256 Mo?

À l'écho 2,3,4 sa jolie utilisation de la mémoire constante. Il descend mon demi-million au point 4. Mais le point 1 est l'endroit où l'augmentation de la mémoire principale se produit. Probablement à cause de file_get_html chargement du fichier html en mémoire.

Je pense que le clear et unset de la variable $html prendrait soin de cela?

function get_stuff($link, $category){ 

    $html = file_get_html(trim("$link")); 

    $article = $html->find('div[class=searchresultsWidget]', 0); 

    echo '1 - > '.convert(memory_get_usage(true)).'<br />'; 

    foreach($article->find('h4 a') as $link){ 

     $next_url = 'http://new.mysite.com'.$link->href; 

     $font_name = trim($link->plaintext);   

     $html = file_get_html(trim("$next_url")); 

     $article = $html->find('form[class=addtags]', 0); 

     $font_tags = ''; 

     foreach($article->find('ul[class=everyone_tags] li a span') as $link){ 

      $font_tags .= trim($link->innertext).','; 

     } 

     echo '2 - > '.convert(memory_get_usage(true)).'<br />'; 

     $font_name = mysql_real_escape_string($font_name); 
     $category = mysql_real_escape_string($category); 
     $font_tags = mysql_real_escape_string($font_tags); 

     $sql = "INSERT INTO tag_data (font_name, category, tags) VALUES ('$font_name', '$category', '$font_tags')"; 

     unset($font_tags); 
     unset($font_name); 
     unset($category); 

     $html->clear(); 

     mysql_query($sql); 

     unset($sql); 

     echo '3 - > '.convert(memory_get_usage(true)).'<br />';  

} 

    unset($next_url); 
    unset($link); 
    $html->clear(); 
    unset($html); 
    unset($article); 

    echo '4 - > '.convert(memory_get_usage(true)).'<br />'; 

} 

Comme vous pouvez le voir, j'ai essayé de faire usage de peu faible. Bien que ce ne soit pas bon comme je le comprends, il ne sera pas "désactivé" la mémoire dès que je l'appelle.

Merci à tous pour toute aide sur la façon dont je peux réduire cette augmentation de la mémoire.

+6

Je reçois un rep neg pour ma question? Comme les notifications utiles de stackoverflow disent. Ne pas simplement rep neg, si vous le faites, suivez-le par un commentaire. – Abs

+1

Je trouve que c'est une bonne question. Peut-être que c'est le mot «sucer» qui a provoqué cela. Upvoted. – Mchl

+0

En php, toute la mémoire utilisée par une requête http est détruite à la fin de la requête. Cependant, le gc est utilisé pour gérer la mémoire pendant le traitement de la requête. Je crois que c'est un simple comptage de ref. – seand

Répondre

8

Il y a une fuite de mémoire connu avec file_get_html(): http://simplehtmldom.sourceforge.net/manual_faq.htm#memory_leak

La solution est d'utiliser

$html->clear(); 

Ce qui vous faites, mais: Vous utilisez html $ à la fois à l'intérieur et à l'extérieur du boucle. À l'intérieur de la boucle, vous appelez $ html-> clear(), puis à nouveau près de la fin de votre fonction $ html-> clear() (je suppose que vous récupérez votre référence d'objet file_get_html() initiale). Ce dernier appel ne fait rien. Vous perdez la mémoire avec l'appel $html = file_get_html() initial. Essayez d'utiliser une variable différente ($ html1, peut-être?) Dans votre boucle et voyez ce qui se passe.

+0

Bonne suggestion, j'essaie que lorsque ce test j'ai cours se termine. Pensez-vous également que l'exécution de ce script PHP à partir de la ligne de commande fera une différence? C'est juste par intérêt. – Abs

+0

"Vous perdez l'association de mémoire avec l'initiale $ html = file_get_html()." Fredonner? Qu'est-ce que ça veut dire? – Artefacto

+0

C'était une bonne suggestion. Il a réussi à diminuer le taux d'augmentation de la mémoire de manière significative! Il n'a pas encore passé 10MB à ce stade. Avant cela aurait été de 120mb ou plus! Je pense que cela fonctionne bien grâce à Jasonbar! :) – Abs

3

Le but du collecteur d'ordures est uniquement d'attraper des références circulaires.

S'il n'y en a pas, les variables sont immédiatement éliminées une fois que leur compte de référence atteint 0.

Je ne recommande pas que vous utilisez unset, sauf dans des cas exceptionnels. Utilisez plutôt des fonctions et utilisez les variables pour sortir de la portée afin de récupérer la mémoire. À part cela, nous ne pouvons pas vous décrire ce qui se passe exactement parce que nous devrions savoir exactement ce que fait le simple analyseur DOM. Il y a peut-être des références circulaires ou des ressources globales contenant une référence, mais il serait difficile de le savoir.

Voir reference counting basics et collecting cycles.

+0

Euh? La récupération de place est une alternative au comptage de références, et elle a l'avantage de ne pas être bernée par des références circulaires. –

+2

@Steven Cela ne veut pas dire que les deux choses ne sont pas utilisées en PHP. – Artefacto

+0

Il est certainement possible d'utiliser les deux, en particulier lorsqu'un système s'interface avec un autre. Par exemple, une application .NET appelant un objet COM a un GC pour le premier mais référence le comptage pour le dernier et doit les faire coopérer. Donc ce que je demande est de savoir si PHP utilise l'un ou l'autre ou les deux (et si oui, quand)? –

2

PHP n'avait pas de ramasse-miettes correct until 5.3. Il utilisait essentiellement le comptage de références, ce qui laissait des références circulaires en place jusqu'à la fin du script (par exemple $a =& $a est circulaire). De plus, le code de nettoyage que DID a fait ne fonctionnerait que si la pression de la mémoire l'exigeait. par exemple. inutile de faire un cycle de nettoyage coûteux si la mémoire nouvellement libérée n'était pas nécessaire. À partir de 5.3, il y a un garbage collector approprié, et vous pouvez le forcer à courir avec gc_enable() et gc_collect_cycles().