2009-11-05 8 views
6

Este es de lejos el software más complejo que he creado y ahora parece que se está quedando sin memoria en algún momento. Todavía no he hecho pruebas exhaustivas, porque estoy un poco perdido sobre cómo abordar el problema.Mi (gran) aplicación arroja una OutOfMemoryException, ¿y ahora qué?

HandleCount: 277 
NonpagedSystemMemorySize: 48136 
PagedMemorySize: 1898590208 
PagedSystemMemorySize: 189036 
PeakPagedMemorySize: 1938321408 
VirtualMemorySize: 2016473088 
PeakVirtualMemory: 2053062656 
WorkingSet: 177774592 
PeakWorkingSet: 883834880 
PrivateMemorySize: 1898590208 
PriviligedProcessorTime: 00:00:15.8593750 
UserProcessorTime: 00:00:01.6562500 
TotalProcessorTime: 00:00:17.5156250 
GDI Objects: 30 
User Objects: 27 

tengo un colector automatizado mundial excepción de que en la excepción recoge la información anterior (usando System.Diagnostics.Process) - junto con la información de excepción, un registro y una captura de pantalla - y me correos electrónicos todo.

Esto ha funcionado bien, ya que he podido eliminar errores según la información enviada por correo electrónico. Esto es, hasta ahora. El software consta de decenas de miles de líneas y utiliza recursos administrados y no administrados.

Podría comenzar a leer el código, línea por línea, pero me da la sensación de que este podría no ser el mejor enfoque para tratar de deducir el problema de acumulación de memoria.

Como nunca antes había hecho este tipo de análisis, ¿cómo sugeriría abordar este tipo de problema?

Respuesta

2

Adjuntar un depurador y reproducir el error. La pila de llamadas en el momento de la excepción debería indicar dónde está el error.

O usted tiene una fuga (s) de memoria, no estamos disponiendo sus objetos, o necesita un mejor hardware :)

+0

en mi humilde opinión, en este caso la captura de la excepción con el depurador será inútil, el daño (fuga de memoria muy probablemente) ya se ha hecho en otro lugar. – Naveen

+0

Solo tirando un par de opciones. No puede doler mirar. – tsilb

+0

tslib tiene un punto, a veces puede reducir cuando se está quedando sin memoria. – Gregory

9

Hay un par de opciones. Los perfiladores de memoria dedicados como ANTS Memory Profiler de RedGate pueden ser muy útiles para solucionar este tipo de problema.

Si no quiere gastar dinero en una herramienta dedicada, también puede usar WinDbg (parte de Debugging tools for Windows, una descarga gratuita de Microsoft). Puede mostrar el uso del montón para el montón administrado, los diversos montones de AppDomain, etc.

Eche un vistazo a this blog para obtener consejos sobre el uso de WinDbg.

Tenga en cuenta que la solución de problemas de memoria puede ser difícil, ya que generalmente no ve el problema real, sino simplemente un síntoma. Por lo tanto, a diferencia de un bloqueo donde la pila de llamadas le dará una buena indicación del origen del problema, las listas de llamadas para un proceso con OOM pueden revelar muy poco.

En mi experiencia, tiene que ver dónde se utiliza la memoria. Podría estar en el montón administrado, en cuyo caso debe averiguar si algo se está acumulando en las instancias más tiempo de lo necesario. Sin embargo, también podría estar relacionado con la carga de muchos ensamblajes (generalmente montajes generados sobre la marcha).

+0

+1 en el generador de perfiles de memoria ANTS! – tijmenvdk

+0

+1 Solo por publicar algo útil. – Gregory

+0

HORMIGAS, gran herramienta. – BennyM

3

Eche un vistazo a este artículo MSDN sobre la detección de fugas de memoria en aplicaciones .NET.

Quizás tenga algunos problemas donde se asigna la memoria y nunca se recopila.

1

Su PeakWorkingSet indica el número común cuando CLR de 32 bits comienza a explotar.

A pesar de lo que la gente le diga, ya pesar de la gran ironía de la administración automática de la memoria, debe ser consciente de esto y asegurarse de nunca acercarse a ese límite en tales sistemas/32 bits. Muchos no se dan cuenta de ello y normalmente me encanta tomar sus votos bajos de C#, pero cuando ejecutas algunas de esas aplicaciones en un solo escritorio, puedes esperar que se produzcan estragos.Basta con mirar la parte administrada del cierre de VS, es como un tren que se ejecuta a través de una PC.

Hay un MemProfiler gratuito para .NET, úselo y busque las raíces colgantes ... eventualmente, y especialmente cuando comience a tratar con datos de tamaño moderado, tendrá que usar el diseño para la transmisión en lugar de confiar en que se ejecutará en x64 con más RAM.

Y tener un conjunto de datos c880MB es patético en estos días ... ¡HECHO!

[Pieza de C# 3.0 ovejas]

10

Se proporciona una herramienta para eso.

http://msdn.microsoft.com/en-us/library/ms979205.aspx

CLR Profiler le permite buscar en el montón administrado de un proceso y investigar el comportamiento del colector de basura . Usando las diversas vistas en la herramienta, puede obtener información útil sobre el consumo de ejecución, asignación y memoria de su aplicación.

Usando CLR Profiler, puede identificar código que asigna demasiada memoria, hace demasiadas basura colecciones, y se aferra a la memoria durante demasiado tiempo.

0

Quizás primero deba verificar los lugares donde usa recursos no administrados. El problema puede ser que no los liberes, o no lo haces correctamente.

2

Tengo exactamente la misma aplicación. :) Nuestra aplicación se usa para llevar hasta 10 GB de RAM. Esto es obviamente malo. Después de un poco de optimización, pude reducir el uso de memoria unas 50 veces, por lo que ahora el mismo conjunto de datos toma hasta 200MB. ¿Magia? No. :) Lo que hice:

  1. Algunos datos se almacenaron en la memoria varias veces (varias copias). Hice una copia de cada grupo de datos.
  2. Algunos datos se almacenaron como string, pero la forma más eficiente es int porque esas cadenas contienen solo dígitos.
  3. La clase principal de almacenamiento de datos fue . We wrote our own dictionary que no almacenan ningún hash, ya que el uso de la memoria resultante disminuyó 3 veces en los sistemas de 64 bits y 2 veces en los sistemas de 32 bits.

Así que mi pregunta es: ¿cuál es la clase/objeto principal que utiliza para almacenar datos? ¿Qué tipo de datos almacenas?

0

Ya se han sugerido muchas soluciones útiles y el artículo de MSDN es muy minucioso. Junto con las sugerencias anteriores, también haría lo siguiente;

Correlacione el tiempo de la excepción con su archivo de registro para ver qué estaba pasando en el momento de la excepción OOM. Si tiene poco registro en el nivel de información o depuración, le sugiero que agregue algunos registros para que tenga una idea del contexto en torno a este error.

¿El uso de memoria aumenta gradualmente durante un largo período de tiempo antes de que la excepción (por ejemplo, un proceso de servidor que se ejecuta indefinidamente) o un salto en grandes aumentos bastante rápidamente hasta la excepción?¿Hay muchos hilos en ejecución o solo uno?

Si la primera es verdadera y la excepción no ocurre durante mucho tiempo, implicaría que los recursos tienen fugas tienen fugas como se indicó anteriormente. Si lo posterior es cierto, varias cosas podrían contribuir a la causa, p. un bucle que asigna mucha memoria por iteración, recibe un gran conjunto de resultados de un servicio, etc.

De cualquier forma, el archivo de registro debe proporcionarle suficiente información sobre dónde empezar. Desde allí, me aseguraría de poder recrear el error ya sea emitiendo un cierto conjunto de comandos en la interfaz o usando un conjunto consistente de entradas. Después de eso, dependiendo del estado del código, trataría (con el uso de la información del archivo de registro) de crear algunas pruebas de integración que apuntaran a la fuente supuesta del problema. Esto debería permitirle recrear la condición de error mucho más rápido y hacer que sea mucho más fácil de encontrar ya que el código en el que se está concentrando será mucho más pequeño.

Otras cosas que suelo hacer es rodear el código sensible a la memoria con una pequeña clase de creación de perfiles. Esto puede registrar el uso de la memoria en el archivo de registro y darle visibilidad inmediata de los problemas en el registro. La clase se puede optimizar para que no se compile en compilaciones de lanzamiento o tenga una pequeña sobrecarga de rendimiento (si necesita más información contácteme). Este tipo de enfoque no funciona bien cuando se asignan muchos hilos

Mencionó recursos no administrados ¿Supongo que se administra todo el código que usted/su equipo ha escrito? De lo contrario, y si fuera posible, rodearía los límites no gestionados con una clase de creación de perfiles similar a la mencionada anteriormente para descartar fugas del código no administrado o la interoperabilidad. Fijar muchos punteros no administrados también puede causar la fragmentación del montón, pero si no tiene un código no administrado, se pueden ignorar ambos puntos.

No se recomienda invocar explícitamente al recolector de elementos no utilizados en un comentario anterior. Aunque rara vez deberías hacer esto, hay momentos en los que es válido (busca el blog de Rico Mariani para ver ejemplos). Un ejemplo (cubierto en el blog mencionado) en el que he llamado explícitamente recopilar es cuando se han devuelto grandes cantidades de cadena de un servicio, se han puesto en un conjunto de datos y luego se han unido a una grilla. Incluso después de que se cerró la pantalla, esta memoria no se recopiló durante un tiempo. En general, no se debe invocar explícitamente ya que el recolector de elementos no utilizados mantiene las métricas sobre las que basa (entre otras cosas) las colecciones. Llamar por cobrar invalida explícitamente estas métricas.

Por último, generalmente es bueno tener una idea de los requisitos de memoria de su aplicación. Puede obtener esto registrando más información, ocasionalmente ejecutando el generador de perfiles, pruebas de estrés/unidad/integración. Obtenga una idea de qué impacto tiene una determinada operación en un nivel alto, p. basado en un conjunto de entradas aproximadamente x serán asignadas. Obtengo una comprensión de esto al cerrar la sesión de información detallada en puntos estratégicos en el archivo de registro. Un archivo de registro inflado puede ser difícil de entender o interpretar.

Cuestiones relacionadas