Perl de perfiles de uso de memoria y detección de fugas?

Escribí un servicio de red persistente en Perl que se ejecuta en Linux.

Desafortunadamente, a medida que se ejecuta, su tamaño de stack residente (RSS) simplemente crece, crece, crece lentamente, pero con seguridad.

Esto a pesar de los esfuerzos diligentes de mi parte para eliminar todas las claves hash innecesarias y eliminar todas las referencias a objetos que de lo contrario harían que los recuentos de referencia permanezcan en su lugar y obstruyan la recolección de basura.

¿Existen buenas herramientas para crear perfiles del uso de memoria asociado con varias primitivas de datos nativas, objetos de referencia de hash bendecidos, etc. dentro de un progtwig Perl? ¿Qué usas para rastrear memory leaks?

Normalmente no paso tiempo en el depurador de Perl o en cualquiera de los varios perfiladores interactivos, por lo que una respuesta cálida, amable y no esotérica sería apreciada. 🙂

Podría tener una referencia circular en uno de sus objetos. Cuando el recolector de basura aparece para desasignar este objeto, la referencia circular significa que todo lo referido por esa referencia nunca será liberado. Puede verificar referencias circulares con Devel :: Cycle y Test :: Memory :: Cycle . Una cosa para intentar (aunque puede ser costoso en el código de producción, así que lo desactivo cuando no está configurado un indicador de depuración) es verificar referencias circulares dentro del destructor para todos sus objetos:

# make this be the parent class for all objects you want to check; # or alternatively, stuff this into the UNIVERSAL class's destructor package My::Parent; use strict; use warnings; use Devel::Cycle; # exports find_cycle() by default sub DESTROY { my $this = shift; # callback will be called for every cycle found find_cycle($this, sub { my $path = shift; foreach (@$path) { my ($type,$index,$ref,$value) = @$_; print STDERR "Circular reference found while destroying object of type " . ref($this) . "! reftype: $type\n"; # print other diagnostics if needed; see docs for find_cycle() } }); # perhaps add code to weaken any circular references found, # so that destructor can Do The Right Thing } 

Puede usar Devel :: Leak para buscar memory leaks. Sin embargo, la documentación es bastante escasa … por ejemplo, ¿dónde se obtiene la referencia $ handle para pasar a Devel::Leak::NoteSV() ? Si encuentro la respuesta, editaré esta respuesta.

Ok, resulta que usar este módulo es bastante sencillo (código robado descaradamente de Apache :: Leak ):

 use Devel::Leak; my $handle; # apparently this doesn't need to be anything at all my $leaveCount = 0; my $enterCount = Devel::Leak::NoteSV($handle); print STDERR "ENTER: $enterCount SVs\n"; # ... code that may leak $leaveCount = Devel::Leak::CheckSV($handle); print STDERR "\nLEAVE: $leaveCount SVs\n"; 

Colocaría la mayor cantidad de código posible en la sección central, con la comprobación leaveCount lo más cerca posible del final de la ejecución (si tiene uno), después de que la mayoría de las variables hayan sido desasignadas como sea posible (si no puede obtener una variable fuera del scope, puede asignar undef a ella para liberar lo que estaba apuntando).

Lo próximo a intentar (sin embargo, no estoy seguro de si esto sería mejor colocarlo en un comentario después de la pregunta de Alex): Lo que probaría a continuación (que no sea Devel :: Leak):

Trata de eliminar partes “innecesarias” de tu progtwig, o segúralo en ejecutables separados (podrían usar señales para comunicarse, o llamarse entre sí con argumentos de línea de comandos) – el objective es reducir un ejecutable en la cantidad más pequeña de código que todavía exhibe el mal comportamiento . Si está seguro de que no es su código el que lo está haciendo, reduzca el número de módulos externos que está utilizando, particularmente aquellos que tienen una implementación XS. Si tal vez es su propio código, busque cualquier cosa potencialmente sospechosa:

  • definitivamente cualquier uso del código Inline :: C o XS
  • uso directo de referencias, por ejemplo, \@list o \%hash , en lugar de referencias preasignadas como [qw (foo bar)] (el primero crea otra referencia que puede perderse, en el último, hay solo una referencia de qué preocuparse, que generalmente se almacena en un escalar léxico local
  • manipular variables de forma indirecta, p. ej. $$foo donde $foo está modificado, lo que puede provocar la autovigilancia de las variables (aunque es necesario deshabilitar la strict 'refs' comprobación de strict 'refs' )

Una buena guía sobre esto se incluye en el manual de Perl: depuración del uso de memoria Perl

Recientemente utilicé NYTProf como un generador de perfiles para una gran aplicación de Perl. No rastrea el uso de la memoria, pero rastrea todas las rutas de código ejecutadas, lo que ayuda a descubrir dónde se originan las fugas. Si lo que está filtrando son recursos escasos, como las conexiones de bases de datos, el rastreo en el que se asignan y cierran hace mucho por encontrar fugas.