2010-08-01 9 views
7

Tengo la siguiente función a la que llamo con mucha frecuencia en un bucle.PHP ¿La recolección de basura es una mierda o solo soy yo?

Esperé 5 minutos mientras la memoria ascendía de 1MB a 156MB. ¿No debería subir el recolector de garabatos de PHP y reducir esto en algún momento?

¿Es porque he configurado el límite de memoria en 256MB?

En el punto de eco 2,3,4 es bastante constante el uso de la memoria. Me baja medio mi mego en el punto 4. Pero el punto 1 es donde ocurre el aumento de la memoria principal. Probablemente debido a file_get_html cargando el archivo html en la memoria.

Yo pensé que la variable $html clara y no configurada se encargaría de esto?

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 />'; 

} 

Como puede ver, intenté hacer uso de unset débilmente. Aunque no es bueno, como entiendo, no "desconectará" la memoria tan pronto como la llame.

Gracias a todos por cualquier ayuda sobre cómo puedo reducir este aumento de la memoria.

+6

obtengo un representante de Negat por mi pregunta? Como dicen las notificaciones útiles de stackoverflow. No se limite a neg rep, si lo hace, sígalo por un comentario. – Abs

+1

Encuentro una buena pregunta en realidad. Tal vez es la palabra 'chupar' lo que provocó esto. Upvoted. – Mchl

+0

En php, toda la memoria utilizada por una solicitud http se anula al final de la solicitud. Sin embargo, el gc se usa para administrar la memoria mientras se procesa la solicitud. Creo que es simple conteo de ref. – seand

Respuesta

8

Hay una pérdida de memoria conocido con file_get_html(): http://simplehtmldom.sourceforge.net/manual_faq.htm#memory_leak

La solución es utilizar

$html->clear(); 

¿Qué está haciendo, pero: ¿Estás usando $ html tanto dentro como fuera de la lazo. Dentro del bucle está llamando $ html-> clear(), y luego cerca del final de su función $ html-> clear() nuevamente (supongo que captará su referencia de objeto inicial file_get_html()). Esa última llamada no hace nada. Está perdiendo memoria con la llamada inicial $html = file_get_html().

Pruebe usar una variable diferente ($ html1, ¿quizás?) Dentro de su ciclo y vea qué pasa.

+0

Buena sugerencia, estoy tratando de que cuando termine esta prueba, termine la ejecución. ¿También crees que ejecutar este script PHP desde la línea de comandos hará la diferencia? Esto es solo por interés. – Abs

+0

"Está perdiendo el asociado de memoria con el $ html inicial = file_get_html()". ¿Tararear? ¿Qué significa esto? – Artefacto

+0

Fue una buena sugerencia. Se las arregló para disminuir la tasa de aumento de memoria significativamente! Hasta ahora no ha superado los 10 MB. ¡Antes de que hubiera estado en 120mb más o menos! ¡Creo que esto está funcionando bien gracias a Jasonbar! :) – Abs

3

El propósito del recolector de basura es solo atrapar referencias circulares.

Si no las hay, las variables se eliminan de inmediato una vez que su cuenta de referencia golpea 0.

No recomiendo que utilice unset, salvo en casos excepcionales. Use funciones en su lugar y confíe en las variables para salir del alcance y reclamar la memoria.

Aparte de eso, no podemos describir lo que está ocurriendo exactamente porque tendríamos que saber exactamente qué está haciendo el analizador DOM simple. Posiblemente haya referencias circulares o recursos globales con una referencia, pero sería difícil de saber.

Ver reference counting basics y collecting cycles.

+0

¿Eh? La recolección de basura es una alternativa al recuento de referencias, y tiene la notable ventaja de no ser engañado por referencias circulares. –

+2

@Steven Eso no significa que ambas cosas no se usan en PHP. – Artefacto

+0

Es ciertamente posible utilizar ambos, especialmente cuando un sistema está interactuando con otro. Por ejemplo, una aplicación .NET que llame a un objeto COM tiene GC para el anterior, pero el conteo de referencia para este último y tiene que hacer que los dos cooperen. Entonces, ¿qué estoy preguntando si PHP usa uno u otro o ambos (y si es así, cuándo)? –

2

PHP no tenía un recolector de basura adecuado until 5.3. Básicamente, solo utilizaba el recuento de referencias, lo que dejaría referencias circulares en su lugar hasta que terminara el guión (por ejemplo, $a =& $a es circular). Además, el código de limpieza que DID tenía solo se ejecutaría si la presión de memoria lo requería. p.ej. no tiene sentido hacer un ciclo de limpieza costoso si no se necesita la memoria recién liberada.

A partir del 5.3, hay un recolector de basura adecuado, y puede forzarlo a ejecutar con gc_enable() y gc_collect_cycles().

Cuestiones relacionadas