2009-05-07 13 views
6

El problema es simple Tengo un proceso, que hace ETL en algunos archivos xml. Comenzamos a obtener archivos xml realmente grandes y comencé a recibir OutOfMemoryExceptions.Cómo hacer que un proceso .NET se quede sin memoria sin agotar toda la memoria del sistema

La reparación del proceso es relativamente simple. Sin embargo, me gustaría hacer una prueba unitaria para mi suite NUnit para asegurarme de que el proceso continúe siendo capaz de manejar archivos realmente grandes. Sin embargo, en realidad, la falta de memoria en mi estación de trabajo de desarrollo ralentiza mi máquina y consume mucho tiempo. También es una mala idea guardar un archivo de prueba enorme en el control de versiones. Si pudiera limitar artificialmente un proceso, thread o appdomain para usar solo una cantidad fija de ram, digamos 128 megas, podría hacer una prueba unitaria más pequeña que no llevara a mi estación de trabajo, de rodillas.

¿Alguna sugerencia? ¿Hay alguna API no administrada que pueda P/Invocar?

+0

Yo no quiero poner esto en mi respuesta principal, porque no está respondiendo exactamente a su pregunta, pero es algo que suena como una cosa rara de probar la unidad. En un nivel alto, su algoritmo para leer los archivos manejará archivos muy grandes de tamaño arbitrario (porque transmite o corta el archivo) o no lo hará. Eso no va a cambiar muy seguido, si es que lo hace, y no veo lo que gana al probarlo cada vez con su conjunto de pruebas, especialmente dado que (si falla) puede no fallar de manera confiable cada vez en un determinado archivo. – mquander

+0

Abro y escaneo el archivo varias veces. A veces lo hago como una transmisión, a veces no lo hago. El 99.9% de los archivos que escaneo son lo suficientemente pequeños como para poder cargar todo el archivo en la memoria. El otro .01% necesita procesar. Por lo tanto, si realizo todas las operaciones de archivo en secuencia (solucionando el problema), alguien podría agregar un nuevo paso que procese el archivo cargándolo todo en la memoria. Sin una prueba unitaria que realice toda la operación de ETL en un archivo lo suficientemente grande como para consumir todo el ram de procesamiento, esto lo convertirá en producción, ya que el control de calidad podría no probar el sistema con un archivo realmente grande. –

+0

Creo que la mejor respuesta aquí es encapsular las operaciones que necesita hacer muy bien, por lo que es difícil para cualquier otra persona ir accidentalmente por la ruta de manejar el archivo y abrir todo para intentar buscar algo. Por supuesto, alguien aún podría ir y piratear su jungla para abrir todo el archivo si lo intentaran lo suficiente, pero creo que podría evitar que alguien lo haga por pura ignorancia. (Sé que esto es accesorio a la discusión sobre cómo probarlo, pero la prevención es la mejor cura). – mquander

Respuesta

0

No entiendo muy bien a qué te refieres aquí. Supongamos que de algún modo creaste un "entorno de prueba" artificialmente pequeño que no podía asignar grandes trozos de memoria, por lo que arrojó OutOfMemoryExceptions en archivos más pequeños. ¿Qué has ganado? Se suponía que la prueba unitaria probaría si puedes manejar archivos más grandes en un sistema real, ¿verdad?

Lo importante es que puede manejar archivos "tan grandes como deben ser" en cualquier sistema en el que se ejecuten, y no existe una forma real de probar la unidad que, además de probar ese archivo en ese sistema.

(Una cosa más pequeña, menos importante podría ser si manejas con gracia OutOfMemoryException s, pero no necesitas quedarte sin memoria para probar eso, solo haz que tu método arroje una excepción de vez en cuando y observa que hace lo correcto.)

+0

La prueba es que el sistema puede manejar archivos arbitrariamente grandes, no archivos realmente grandes. En otras palabras, todas las operaciones de archivos se realizan sin cargar todo el archivo en la memoria, y no debe haber límite en la cantidad de archivos que el sistema podría manejar. –

2

¿No puede usar un marco de burla para la asignación de memoria y hacer que arroje OutOfMemoryException como una de las pruebas?

Dicho esto, si realmente se ha quedado sin memoria no hay mucho que su aplicación pueda hacer de manera segura, pero si al menos puede fallar con elegancia, sus usuarios estarán agradecidos.

Un ejemplo: que tenía un caso en un trabajo anterior en el que mostraban modelos 3D de fábricas en tiempo real. Los modelos crecieron tanto que cuando tratábamos de cargar texturas salíamos de fallas de memoria. Logramos mantener la aplicación viva y renderizada, asegurándonos de que el código hiciera frente a punteros nulos, aunque el resto del código pensó que debería haber información sobre texturas allí.

+0

Solo iba a sugerir lo mismo con respecto a objetos simulados. – RichardOD

1

Burlarse es lo mejor. En realidad, elevar un OOM es, por definición, no una prueba unitaria. Cuando se trata de memoria, se trata de pruebas de carga. Si lee los enlaces en la parte inferior de este correo electrónico, encontrará que los OOM reales son extremadamente difíciles de reproducir y depurar en el mejor de los casos. Una excepción artificial OOM no es la verdadera causa de la excepción, y por lo tanto no es más interesante que un simulacro de prueba.

Stick con una prueba de unidad usando un simulacro para validación. Si aún obtiene OOM, agregue más memoria a su servidor y haga que su proceso se recicle/reinicie con más frecuencia.

He aquí una lectura interesante sobre OutMemoryExceptions que recopilé la última vez que peleé con ellos. Resumen: los OOM se producen cuando el sistema no puede asignar la cantidad que solicitó, lo que no significa que no tenga memoria.

+0

"Si todavía obtiene OOM, agregue más memoria en su servidor y haga que su proceso se recicle/reinicie con más frecuencia". Agregar más memoria no afecta el problema ... se está quedando sin memoria virtual en el proceso. La memoria física no es el problema. Suponiendo que se ejecuta en una plataforma de 32 bits, tiene 2 GB para el espacio de direcciones de la aplicación que puede asignar a través de ambos montones y la pila. Los OOM ocurren cuando no se puede asignar suficiente memoria contigua en el espacio de direcciones. –

0

Es bastante fácil de hacer excepciones de memoria insuficiente en un proceso.

Simplemente cree un bucle que asigne memoria en bloques que sean lo suficientemente pequeños como para no estar en el gran montón de objetos (pero no demasiados que tenga la excepción) y luego intente abrir un archivo más pequeño y que hará que la apertura del archivo no sea capaz de asignar suficiente memoria contigua y obtendrá su excepción OOM al abrir su archivo sin necesidad de un gran archivo. Algo como esto ...

List<byte[]> items = new List<byte[]>(); 
for (int i = 0; i < 10000; i++) 
{ 
    byte[] c = new byte[160000]; 
    items.Add(c); 
} 

byte[] next = new byte[1000000000]; 

Si ejecuta el código anterior como es, obtendrá una excepción OOM en la última línea. Pero, si comenta primero el bucle, se ejecutará sin errores. Probablemente tendrá que ajustar un poco el ciclo para que el archivo abierto siempre falle, pero puede hacerlo. Simplemente ejecute el ciclo antes de su llamada para abrir su archivo en la prueba y habrá agotado una gran cantidad de memoria y su apertura fallará.

Además, es posible que desee considerar la configuración del modificador/3GB si es una opción para usted. No siempre es la respuesta correcta y tiene inconvenientes asociados, pero cambia la división de memoria virtual de 2 GB/2 GB a 1 GB/3 GB, lo que permite que su proceso acceda a más espacio de direcciones virtuales. Esto le dará un poco más de espacio para respirar en el tamaño de los archivos que puede abrir. Una vez más, debe leer acerca de los inconvenientes de hacer esto antes de buscar esto como una solución y asegurarse de que valga la pena si ayuda a su situación.

Here es cómo habilitarlo en el servidor

Cuestiones relacionadas