Las referencias circulares son
de lejos la más común
la causa canónica de fugas.
sub leak {
my ($foo, $bar);
$foo = \$bar;
$bar = \$foo;
}
Perl usa la cuenta de referencia para la recolección de basura. Esto significa que perl lleva un recuento de qué punteros a cualquier variable existen en un momento dado. Si la variable sale del alcance y el recuento es 0, la variable se borra.
En el código de ejemplo anterior, $foo
y $bar
Nunca se recogen y una copia persistirá después de cada invocación de leak()
debido a que ambas variables tienen un contador de referencia de 1.
La forma más sencilla para evitar este problema es utilizar referencias débiles Las referencias débiles son referencias que sigue para acceder a los datos, pero no cuentan para la recolección de basura.
use Scalar::Util qw(weaken);
sub dont_leak {
my ($foo, $bar);
$foo = \$bar;
$bar = \$foo;
weaken $bar;
}
En dont_leak()
, $foo
tiene un contador de referencia de 0, $bar
tiene un recuento de ref 1. Cuando dejamos el alcance de la subrutina, $foo
se devuelve a la piscina, y se borra su referencia a $bar
. Esto reduce el conteo de ref en $bar
a 0, lo que significa que $bar
también puede regresar al grupo.
Actualización: brain d foy me preguntaron si tenía datos para respaldar mi afirmación de que las referencias circulares son comunes. No, no tengo ninguna estadística para mostrar que las referencias circulares son comunes. Son la forma más común y mejor documentada de pérdidas de memoria perl.
Mi experiencia es que suceden. Aquí hay un resumen rápido de las pérdidas de memoria que he visto durante más de una década de trabajo con Perl.
He tenido problemas con las aplicaciones pTk que desarrollan fugas. Algunas filtraciones que pude probar se debieron a referencias circulares que surgieron cuando Tk pasa las referencias de ventana. También he visto fugas de pTk cuya causa nunca podría rastrear.
He visto a la gente malinterpretar weaken
y terminar con referencias circulares por accidente.
He visto ciclos involuntarios surgir cuando demasiados objetos mal pensados se juntan a toda prisa.
En una ocasión encontré fugas de memoria que provenían de un módulo XS que estaba creando estructuras de datos grandes y profundas. Nunca pude obtener un caso de prueba reproducible que fuera más pequeño que todo el programa. Pero cuando reemplacé el módulo con otro serializador, las filtraciones desaparecieron. Entonces sé que esas filtraciones vinieron del XS.
Por lo tanto, en mi experiencia los ciclos son una fuente importante de fugas.
Afortunadamente, there is a module para ayudar a rastrearlos.
En cuanto a si las grandes estructuras globales que nunca se limpian constituyen "fugas", estoy de acuerdo con Brian. Graznan como goteras (tenemos un uso cada vez mayor de la memoria de proceso debido a un error), por lo que son fugas. Aun así, no recuerdo haber visto este problema en particular en la naturaleza.
Basado en lo que veo en el sitio de Stonehenge, supongo que Brian ve un montón de código de enfermedad por parte de las personas para las que está entrenando o que está preparando milagros curativos. Entonces, su conjunto de muestras es mucho más grande y variado que el mío, pero tiene su propio sesgo de selección.
¿Qué causa de fugas es la más común? No creo que lo sabremos nunca. Pero todos podemos estar de acuerdo en que las referencias circulares y los depósitos de datos globales son antipatrones que deben eliminarse siempre que sea posible, y deben manejarse con cuidado y precaución en los pocos casos en que tengan sentido.
¿Cómo atrapó estas fugas de memoria? ¿Has probado Perl Profiler (http://www.perlmonks.org/?node_id=472366)? –