2012-06-06 13 views
10

que leer sobre límite de memoria1,2 GB de memoria excepción

tengo una aplicación que funciona con enormes imágenes que debe ser transmitido. Como en un procesamiento de video con marcos individuales. La aplicación tiene aproximadamente 40 complementos, cada uno de ellos puede contener bases de datos, procesamiento de imágenes y GUI de WPF.

La aplicación también tiene 2 complementos que utilizan formas de pago DotNet anteriores.

Todo funciona bien, excepto que la aplicación supera los 1,2 GB en RAM. Luego, en ubicaciones inusuales en los complementos donde se asigna nueva memoria, recibo la "excepción de falta de memoria".

Estoy trabajando en un sistema de 64 bits compilado como 32 bits. No tengo más idea de qué hacer y cómo buscar cualquier falla.

¿Hay un límite o puedo obtenerlos?

+0

¿cuántos usuarios se necesitan para llegar al límite? – Limey

+0

No entiendo la pregunta. Las imágenes son 1500x1500 píxeles y todo funciona bien. Con el mismo código y los mismos procedimientos, si la resolución de la imagen de origen de la transmisión de video es 3500x3500, la aplicación se bloquea con la excepción de memoria. Pero la computadora tiene más de 3GB de RAM disponible y gratis. – Nasenbaer

+1

Me gustaría un profiler _memory_ (es decir, no un _performance_ profiler) como [ANTS Memory Profiler] (http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/). –

Respuesta

19

Es muy difícil escribir un programa de 32 bits que consuma todos del espacio de memoria virtual disponible. Golpearás la pared muy por debajo de 2 gigabytes, lo que se te acaba primero es un trozo de memoria virtual que es lo suficientemente grande para ajustarse al tamaño solicitado. Solo puede obtener hasta el límite de 2 GB haciendo pequeñas asignaciones, lo suficientemente pequeñas como para caber en los agujeros.

Ese muro golpea temprano en un programa que manipula bitmaps. Pueden consumir una gran parte de la máquina virtual para almacenar los píxeles del mapa de bits y debe ser una asignación contigua. Se almacenan en un array, no en un tree. Es una asignación de memoria no administrada, los perfiladores de memoria .NET típicos tienden a ser un poco impotentes para mostrarle el problema.

No hay nada razonable que pueda hacer sobre la fragmentación del espacio de direcciones, la noción de que consumir todas las VM disponibles debería ser posible es simplemente incorrecta. Puede obtener más espacio en un sistema operativo de 64 bits ejecutando editbin.exe en un post build event y use su opción de línea de comando /LARGEADDRESSAWARE. Eso permite que el proceso use los 4 gigabytes disponibles de VM, una opción que es específica para la versión de 64 bits de Windows y es posible porque Windows no necesita los 2 GB superiores. Y, por supuesto, cambiar el objetivo de la plataforma a AnyCPU es una manera rápida y fácil de obtener montones de memoria virtual.

0

Una aplicación de 32 bits que se ejecuta en Windows (incluso si el sistema operativo es de 64 bits) tiene un espacio de direcciones de 4 Gb, pero esta se divide en 2Gb Application/2Gb System (esto puede cambiarse a 3/1 con un conmutador de inicio diferente).

Es bastante probable que la memoria total que está utilizando sea en realidad 2Gb en lugar de 1.2Gb, ¿cómo está determinando esta figura de 1.2Gb? ¿Ha mirado la aplicación con la herramienta process explorer?

Si cambia su aplicación a ANYCPU o 64Bit, debería encontrar que esta limitación desaparece (bueno, se mueve a un valor enormemente mayor) en un sistema operativo de 64 bits.

+7

Agrega información. 2GB es para aplicaciones no administradas. Para las aplicaciones administradas, OOM tiene aproximadamente 1.2-1.5GB aproximadamente debido a GC. cambiar a 64 bits puede resolver el problema, pero puede ser imposible si alguna de las dependencias tiene solo 32 bits. –

0

Para ser más determinista, debe escribir algunas pruebas de integración para verificar dónde termina su memoria. Puede hacerlo ahora con WMemoryProfiler.Primero cargaba las imágenes en un tamaño de 1500x1500, limpiaba todo y marcaba todos los objetos como se sabe. Luego, volvía a colocar las imágenes grandes y verificaba qué objetos nuevos se asignaban y tenía una visión nítida de cuántos de ellos están allí y quién los posee.

Usted dice que hay muchos módulos externos utilizados. Tal vez deberías abandonar algunos de ellos debido al uso imprudente de la memoria y reemplazarlos por algo mejor. Ahora puedes verificar.

Si está llegando al límite, todavía puede descargar algunas imágenes y cargarlas bajo demanda si usted y sus complementos son compatibles con estructuras perezosas como IEnumerable<Image> donde usted como proveedor puede decidir cuándo cargar las imágenes y cuánto tiempo guardarlas en un caché hasta que se deshaga de la referencia para ayudar a liberar algo de memoria.

[Test] 
public void InstanceTracking() 
{ 
    using (var dumper = new MemoryDumper()) // if you have problems use to see the debugger windows true,true)) 
    { 
     TestWith1500x1500(); 
     dumper.MarkCurrentObjects(); 
     TestWith3000x3000(); 
     ILookup<Type, object> newObjects = dumper.GetNewObjects() 
               .ToLookup(x => x.GetType()); 

     // here we do find out which objects are holding most of the memory 
     MemoryStatistics statOld = dumper.GetMemoryStatistics(); 
     foreach (var typeInfo in statOld.ManagedHeapStats 
            .OrderByDescending(x => x.Value.Count)) 
     { 
      Console.WriteLine("Type {0} has {1} instances of total size {2:N0} bytes", 
          typeInfo.Key, 
          typeInfo.Value.Count, 
          typeInfo.Value.TotalSize); 
     } 

     // then check with the info from above who is holding the most interesting new objects. 
     Console.WriteLine("New Strings:"); // just an example perhaps you should have a look at the images. 
     foreach (var newStr in newObjects[typeof(string)]) 
     { 
      Console.WriteLine("Str: {0}", newStr); 
     } 
    } 
} 
Cuestiones relacionadas