2010-09-13 10 views
5

Corrí un código el viernes pasado antes de dejar el trabajo, y estoy aquí el lunes, y se detuvo con una OutOfMemoryException. Todo este proceso que estimo requería hacer decenas de miles de millones de cálculos, por lo que no era una tarea pequeña.Cómo diagnosticar una excepción System.OutOfMemoryException?

Ni siquiera sé cómo comenzar a arreglar esto.
¿Alguna sugerencia?

+5

¿Utiliza un perfilador de memoria? – dtb

+0

¿Tiene alguna recomendación para una? – sooprise

+3

¡Agrega más memoria! ;) – w69rdy

Respuesta

6

Bueno, dada la Contet que ya ha proporcionado, o la falta de ella, lo único que puede proporcionar algunas ideas generales aquí: En primer lugar, la respuesta obvia sería tomar una mirada a la información contenida en la excepción misma, que debería darle una idea de dónde falló la asignación de código.

En segundo lugar, emplea perfiles de memoria para tener una mejor idea de lo que está sucediendo en su aplicación - Soy un usuario de dotTrace, pero puede haber alternativas gratuitas disponibles.

Aparte de este advenimiento general, es posible que desee incluir algo más de información en su pregunta. ¿Qué tipo de objetos va a asignar, cuando se va a asignar, ¿Está utilizando los recursos nativos etc.

+0

Recomiendo totalmente dotTrace. –

1

Aaah ... esta es una de las excepciones que realmente no desea obtener en su aplicación. Obtuvimos esta excepción también en nuestro proyecto y utilizamos el profiler de memoria .net para verificar los usos y fugas de la memoria. Hasta cierto punto, podríamos reducir la frecuencia de salir de la excepción de memoria. A continuación se realiza el enlace de perfiles -

http://memprofiler.com/

+0

He encontrado que el perfilador SciTech es más fácil de usar que ANTS. Vale la pena intentarlo. – spender

+0

@spender - Gracias por esto. También podemos probar en este nuevo generador de perfiles. ¿Puedes proporcionar un enlace a este perfilador de SciTech? –

+0

Es el que está vinculado a: http://memprofiler.com – spender

1

Es necesario identificar cuál fue la causa, de donde vino, y luego puede ver cómo se reescribe esa sección para que use menos memoria, tal vez dividiéndola en pedazos y luego liberando algunos recursos.

Intente introducir un registro en algún lugar (haciendo el paso 1, paso 2) con marcas de tiempo para ayudar a identificar dónde está fallando, luego puede formular una pregunta más específica sobre la reducción de la dependencia de memoria si no es obvio.

3

Hay varias cosas que puedes probar.

Primero, haga un pase aproximado con el Monitor de rendimiento, integrado en Windows. Agregue un contador para Proceso -> bytes privados utilizados, y ajuste la escala en consecuencia para que pueda echar un rápido vistazo al uso de la memoria. En lugar de esperar durante la noche, podrá identificar una fuga un poco antes. Otro contador que puedes probar se encuentra en .NET Memory, pero como mi monitor de rendimiento no me deja agregar los contadores de .NET (¡ARGH!), No puedo decirte exactamente qué es la supresión.

¿Se le asigna memoria a través de un código no administrado en su función de cálculo? Si es así, ¿estás desechando la memoria correctamente? Cualquier código que escriba que asigne memoria de esta manera debe implementar IDisposable, y también debe llamar a Dispose() en estas clases para asegurarse de que se limpien.

¿Llamas recursivamente a tu función? Podrías asignar toneladas de memoria cada vez a través de tu función, y aunque no puedas volar la pila, estarás usando todo el montón.

¿Hay memoria de la que pueda deshacerse antes? Incluso si no está usando un código no administrado, aún puede marcar su código administrado para que el recolector de elementos no utilizados lo elimine antes y luego no termine en el montón de Gen2. Implementa IDisposable, y luego llama a Dispose() en las clases que ya no necesitas seguir.

¿Estás utilizando hilos? Podría asignar memoria a su hilo y si no maneja adecuadamente los errores llamando a EndInvoke, huérfana memoria de esta manera.

Si falla todo lo demás, intente con un generador de perfiles de memoria como ANTS5 de RedGate. Encontró otro error en mi código, donde estaba registrando un controlador de eventos, pero no anulando el registro. Como resultado, mi código colgaba de todos los bits y piezas relacionados con este evento, que lamentablemente también se colgaba de los bits de la memoria. :)

Espero que esto ayude. He pasado por todo esto recientemente y estos son los consejos más útiles que puedo encontrar en este momento.

+0

ANTS es bastante bueno. –

2

Supongo que está almacenando los resultados de sus cálculos en un contenedor como una lista o una matriz. Intente escribir sus resultados en el archivo en lugar de almacenarlos en la memoria.

+0

Está en una matriz estática, por lo que cada instancia de la clase en la que se encuentra puede agregarse. Hay aproximadamente 12 millones de instancias de esta clase en mi programa. Si esta matriz estática es la razón por la cual aparece este error, ¿cómo puedo administrar mejor la memoria que está utilizando esta matriz? – sooprise

5

La solución más simple, más directa sería la siguiente:

  1. Uso procdump (incluido en Sysinternals Suite) para tomar un volcado de memoria completa de su proceso cuando alcanza cierto tamaño razonable.
  2. cargar el volcado en WinDbg y también cargar el SOS extensión de depuración utilizando .loadby sos clr
  3. Utilice el siguiente comando: !dumpheap -stat con el fin de ver qué clase de objetos ocupa la mayor parte de la memoria.
  4. volquete de la lista de objetos (del tipo de fugas) usando !dumpheap -type <MY_TYPE>
  5. Elija un par de casos, y ejecute el comando: !gcroot <OBJ_ADDRESS>. La salida debería decirle qué objeto todavía contiene una referencia a él, y por qué ese objeto no se libera.

En caso de que sospeche que el origen de la fuga proviene de algún código nativo, puede verificarlo emitiendo el siguiente comando: !eeheap -gc. La salida le indicará cuánta memoria necesita el almacenamiento dinámico administrado. Si el tamaño del conjunto de trabajo privado de Process es sustancialmente mayor que el tamaño del montón administrado, es probable que tenga una fuga nativa en sus manos (o, quizás por algún motivo, haya engendrado mucho de hilos, por lo que se está quedando sin espacio debido a las pilas del hilo [puede comprobar cuántos hilos se engendran en su proceso al emitir este comando: ~*, o: !threads para mostrar solo los gestionados]).

+0

+1 Para incluir los comandos de SOS. –

2

Si va a asignar matrices muy grandes repetidamente, puede estar ejecutándose en Large Object Heap Fragmentation. Si este es el caso, es posible que deba considerar si puede reutilizar las matrices de trabajo para evitar las reasignaciones y la posterior fragmentación. Sin embargo, definitivamente recomiendo ejecutar un generador de perfiles de memoria, ya que es más probable que tenga algo persistente en la memoria más allá de lo que asumió que era su fecha de caducidad.

+0

Estoy usando una matriz estática para que cada instancia de la clase en la que se encuentra pueda agregarse. Hay aproximadamente 12 millones de instancias de esta clase en mi programa. Si esta matriz estática es la razón por la cual aparece este error, ¿cómo puedo administrar mejor la memoria que está utilizando esta matriz? – sooprise

+1

La matriz es estática, como en un miembro estático de la clase? Si ese es el caso, no esperaría que cause la fragmentación de LOH, ya que solo es una matriz única. –

Cuestiones relacionadas