¿Cómo encontrar la fuente del uso creciente de memoria de un servidor torcido?

Tengo un servidor de transmisión de audio escrito en Python y basado en Twisted. Funciona bien, pero su uso de memoria está aumentando cuando hay más usuarios en el servidor, pero el uso de la memoria nunca disminuye cuando esos usuarios se desconectan. Como se ve en la siguiente figura: texto alternativo http://static.ez2learn.com/temp/mem_figure3.svg

Puede ver que la curva de uso de la memoria sube donde la curva de los oyentes / radios aumenta, pero después del pico de oyentes / radios, el uso de la memoria sigue siendo alto, nunca baja.

He intentado el siguiente método para resolver este problema:

  1. Mejora Twisted de 8.2 a 9.0
  2. Usa guppy para volcar el montón, pero no ayuda en absoluto
  3. Cambie el selector de reactor a epoll reactor, mismo problema.
  4. Usa objgraph para dibujar el diagtwig de la relación de los objetos, pero no puedo ver puntos de eso.

Aquí está el entorno que utilicé para ejecutar mi servidor torcido:

  • Python: 2.5.4 r254: 67916
  • SO: Linux versión 2.6.18-164.9.1.el5PAE (mockbuild@builder16.centos.org) (gcc versión 4.1.2 20080704 (Red Hat 4.1.2-46))
  • Twisted: 9.0 (bajo virtualenv)

El vertedero de guppy:

Partition of a set of 116280 objects. Total size = 9552004 bytes. Index Count % Size % Cumulative % Type 0 52874 45 4505404 47 4505404 47 str 1 5927 5 2231096 23 6736500 71 dict 2 29215 25 1099676 12 7836176 82 tuple 3 7503 6 510204 5 8346380 87 types.CodeType 4 7625 7 427000 4 8773380 92 function 5 672 1 292968 3 9066348 95 type 6 866 1 82176 1 9148524 96 list 7 1796 2 71840 1 9220364 97 __builtin__.weakref 8 1140 1 41040 0 9261404 97 __builtin__.wrapper_descriptor 9 2603 2 31236 0 9292640 97 int 

Como puede ver, el tamaño total de 9552004 bytes es de 9.1 MB , y puede ver el rss reportado por el comando ps:

 [xxxx@webxx ~]$ ps -u xxxx-o pid,rss,cmd PID RSS CMD 22123 67492 twistd -y broadcast.tac -r epoll 

El rss de mi servidor es de 65.9 MB , lo que significa que hay 56.8 MB de uso de memoria invisible en mi servidor, ¿cuáles son?

Mis preguntas son:

  1. ¿Cómo encontrar la fuente del uso creciente de la memoria?
  2. ¿Qué es el uso de memoria visible para guppy?
  3. ¿Cuáles son esos usos de memoria invisible?
  4. ¿Es eso causado por las memory leaks de algunos módulos escritos en C? Si es así, ¿cómo puedo rastrear y arreglar eso?
  5. ¿Cómo maneja Python la memoria? Grupo de memoria? Creo que esto podría ser causado por trozos de datos de audio. De modo que hay pequeñas fugas en el fragmento de memoria propiedad del intérprete de Python.

Actualización 2010/1/20 : Es interesante, descargo el último archivo de registro y muestra que la memoria nunca aumenta en un momento. Creo que podría ser el espacio de memoria asignado es lo suficientemente grande. Aquí está la última figura. texto alternativo http://static.ez2learn.com/temp/mem_figure4.svg

Actualización 2010/1/21 : Otra figura aquí. hum … elevar un poco el texto alternativo http://static.ez2learn.com/temp/mem_figure6.svg

Vaya … aún subiendo texto alternativo http://static.ez2learn.com/temp/mem_figure7.svg

Como supongo, se debe a un problema de fragmentación de la memoria. El diseño original es mantener los fragmentos de datos de audio en una lista, todos ellos no están en tamaño fijo. Una vez que el tamaño total de la lista de búferes supera el límite de búfer, aparece algunos fragmentos de la parte superior de la lista para limitar el tamaño. Podría verse así:

  1. tamaño de trozo 511
  2. tamaño de trozo 1040
  3. tamaño de trozo 386
  4. tamaño de trozo 1350

La mayoría de ellos son más grandes que 256 bytes, Python usa malloc para trozos que son más grandes que 256 bytes en lugar de usar el conjunto de memoria. Y puedes imaginar que esos trozos están asignados y liberados, ¿qué sucedería? Por ejemplo, cuando se libera el fragmento con un tamaño de 1350, entonces puede haber un espacio libre de 1350 bytes en el montón. Después de eso, viene otra solicitud 988, una vez que malloc recoge el agujero, y luego hay otro pequeño agujero nuevo de tamaño 362. Después de una larga carrera, hay más y más pequeños agujeros en montones, en otras palabras, hay tantos Muchos fragmentos en montones. El tamaño de la página de la memoria virtual por lo general es de 4 KB, esos fragmentos se distribuyen alrededor de un gran rango de almacenamiento dynamic, lo que hace que el sistema operativo no pueda intercambiar esas páginas. Por lo tanto, el RSS siempre es alto.

Después de la modificación del diseño del módulo de administración de fragmentos de audio de mi servidor, ahora usa poca memoria. Puedes ver la figura y compararla con la anterior.

texto alternativo http://static.ez2learn.com/temp/new_mem_figure.svg

El nuevo diseño usa bytearray en lugar de una lista de cadenas . Es una gran parte de la memoria, por lo que no hay más fragmentación.

Suena como una pérdida de memoria en un módulo C para mí. Valgrind es una buena herramienta para rastrear problemas relacionados con la asignación de memoria. No sé cuán bien funciona con los módulos cargados en tiempo de ejecución, aunque …

¿Has pensado en utilizar la alternativa de CentOS a dtrace ? Creo que se llama SystemTap .

Esto debería proporcionarle un rastro de nivel bastante bajo de lo que está sucediendo dentro de sus procesos * nix …….. una puñalada en la oscuridad, pero podría darle un poco más de transparencia en la actividad intraproceso.

Sin embargo, una pregunta interesante. Mirando hacia adelante para ver las respuestas de otros.

Ben