recorrer operaciones nxm matriz matrices iniciador imprimir declaración declaracion con c# arrays garbage-collection xna out-of-memory

nxm - operaciones con matrices en c#



Forzar recolección de basura de matrices, C# (10)

¿No es esto solo una gran fragmentación de objetos? Los objetos> 85,000 bytes se asignan en el montón de objetos grandes. El GC libera espacio en este montón, pero nunca compacta los objetos restantes. Esto puede resultar en una memoria contigua insuficiente para asignar con éxito un objeto grande.

Alan

Tengo un problema donde un par de arreglos tridimensionales asignan una gran cantidad de memoria y el programa a veces necesita reemplazarlos por otros más grandes / pequeños y lanza una excepción OutOfMemoryException.

Ejemplo: hay 5 arrays de 96MB asignados (200x200x200, 12 bytes de datos en cada entrada) y el programa necesita reemplazarlos con 210x210x210 (111MB). Lo hace de una manera similar a esto:

array1 = new Vector3[210,210,210];

Donde array1-array5 son los mismos campos utilizados anteriormente. Esto debería establecer las matrices antiguas como candidatas para la recolección de basura, pero al parecer el GC no actúa con la suficiente rapidez y deja las matrices antiguas asignadas antes de asignar las nuevas, lo que provoca la OOM, mientras que si se liberaron antes de las nuevas asignaciones, el espacio debería estar suficiente.

Lo que busco es una manera de hacer algo como esto:

GC.Collect(array1) // this would set the reference to null and free the memory array1 = new Vector3[210,210,210];

No estoy seguro de si una colección de basura completa sería una buena idea ya que ese código puede (en algunas situaciones) necesitar ser ejecutado con bastante frecuencia.

¿Hay una forma adecuada de hacer esto?


Entiendo que lo que estás tratando de hacer y presionar para la recolección inmediata de basura probablemente no sea el enfoque correcto (ya que el GC es sutil en sus formas y rápido para enojarse).

Dicho esto, si quieres esa funcionalidad, ¿por qué no crearla?

public static void Collect(ref object o) { o = null; GC.Collect(); }


Es posible que no se estén recolectando porque se están haciendo referencias en algún lugar que no estás esperando.

Como prueba, intente cambiar sus referencias a WeakReferences en WeakReferences lugar y vea si eso resuelve su problema de OOM. Si no es así, entonces estás haciendo referencia a ellos en otro lugar.


Esta no es una respuesta exacta a la pregunta original, "cómo forzar GC", sin embargo, creo que le ayudará a volver a examinar su problema.

Después de ver tu comentario,

  • Poner el GC.Collect (); parece ayudar, aunque todavía no resuelve el problema por completo, por alguna razón, el programa aún falla cuando se asignan aproximadamente 1.3GB (estoy usando System.GC.GetTotalMemory (falso); para encontrar la cantidad real asignada).

Sospecharé que puede tener fragmentación de la memoria . Si el objeto es grande (85000 bytes bajo .net 2.0 CLR si recuerdo bien, no sé si se ha cambiado o no), el objeto se asignará en un montón especial, Large Object Heap (LOH) . GC recupera la memoria utilizada por los objetos inalcanzables en LOH, sin embargo, no realiza la compactación, en LOH como lo hace con otros montones (gen0, gen1 y gen2), debido al rendimiento.

Si con frecuencia asigna y desasigna objetos grandes, LOH se fragmentará y, aunque tenga más memoria libre en total de lo que necesita, es posible que ya no tenga más espacio en la memoria contigua, por lo tanto, obtendrá la excepción OutOfMemory.

Puedo pensar dos soluciones en este momento.

  1. Muévase a una máquina / sistema operativo de 64 bits y aprovéchelo :) (Más fácil, pero posiblemente también más difícil dependiendo de sus limitaciones de recursos)
  2. Si no puede hacer el # 1, intente primero asignar una gran cantidad de memoria y usarlas (puede ser necesario escribir alguna clase auxiliar para manipular una matriz más pequeña, que de hecho reside en una matriz más grande) para evitar la fragmentación. Esto puede ayudar un poco, sin embargo, puede que no resuelva completamente el problema y que tenga que lidiar con la complejidad.

Forzar una recolección de basura no siempre es una buena idea (en realidad puede promover la vida útil de los objetos en algunas situaciones). Si tienes que hacerlo, usarías:

array1 = null; GC.Collect(); array1 = new Vector3[210,210,210];


John, Crear objetos> 85000 bytes hará que el objeto termine en el montón de objetos grandes. El montón de objetos grandes nunca se compacta, en lugar de eso, el espacio libre se reutiliza nuevamente. Esto significa que si está asignando matrices más grandes cada vez, puede terminar en situaciones donde LOH está fragmentada, por lo tanto, la OOM.

puede verificar que este es el caso si rompe con el depurador en el punto de OOM y obtiene un volcado, enviar este volcado a MS a través de un error de conexión ( http://connect.microsoft.com ) sería un buen comienzo.

Lo que puedo asegurarles es que el GC hará lo correcto al tratar de satisfacer su solicitud de asignación, esto incluye el lanzamiento de un GC para limpiar la basura antigua para satisfacer las nuevas solicitudes de asignación.

No sé cuál es la política de compartir volcados de memoria en , pero me complacería echarle un vistazo para comprender mejor su problema.



Parte del problema puede ser que esté asignando una matriz multidimensional, que se representa como un único bloque de memoria contiguo en el montón de objetos grandes (más detalles here ). Esto puede bloquear otras asignaciones ya que no hay un bloque contiguo libre para usar, incluso si todavía hay espacio libre en alguna parte, por lo tanto, el OOM.

Intente asignarlo como una matriz irregular, Vector3 [210] [210] [210], que distribuye las matrices alrededor de la memoria en lugar de como un solo bloque, y vea si eso mejora las cosas


Si tuviera que especular, su problema no es realmente que vaya de Vector3 [200,200,200] a Vector3 [210,210,210] sino que probablemente tenga pasos previos similares antes de este:

i.e. // first you have Vector3[10,10,10]; // then Vector3[20,20,20]; // then maybe Vector3[30,30,30]; // .. and so on .. // ... // then Vector3[200,200,200]; // and eventually you try Vector3[210,210,210] // and you get an OutOfMemoryException..

Si eso es cierto, sugeriría una mejor estrategia de asignación. Intente sobre asignar: tal vez duplique el tamaño cada vez en lugar de asignar siempre solo el espacio que necesita. Especialmente si estos arreglos son utilizados por objetos que necesitan anclar los búferes (es decir, si tienen vínculos con el código nativo)

Entonces, en lugar de lo anterior, ten algo como esto:

// first start with an arbitrary size Vector3[64,64,64]; // then double that Vector3[128,128,128]; // and then.. so in thee steps you go to where otherwise // it would have taken you 20.. Vector3[256,256,256];


Una excepción OutOfMemory desencadena internamente un ciclo de GC automáticamente una vez e intenta la asignación nuevamente antes de lanzar la excepción a su código. La única forma en que podría tener excepciones de OutOfMemory es si mantiene referencias a demasiada memoria. Borre las referencias lo antes posible asignándoles un valor nulo.