Pregunta

Tengo un problema donde un par 3 dimensionales asignan una gran cantidad de memoria y el programa a veces necesita reemplazarlas por otras más grandes / más pequeños y lanza una OutOfMemoryException.

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

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

Donde array1-array5 son los mismos campos utilizados anteriormente. Esto debería establecer las viejas matrices como candidatos para la recolección de basura, pero al parecer la GC no actuar con la suficiente rapidez y deja las viejas matrices asignados antes de asignar los nuevos - que hace que el OOM - mientras que si fueran liberados antes de que las nuevas asignaciones del espacio debe ser suficiente.

Lo que estoy buscando 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 un | recogida de basura llena sería una buena idea ya que el código puede (en algunos casos) deben ser ejecutados con bastante frecuencia.

¿Hay una manera correcta de hacer esto?

¿Fue útil?

Solución

Esto 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 su comentario,

  • Poner el GC.Collect (); parece ayudar, madrugada, todavía no resuelve el problema por completo - por alguna razón, el programa vuelve a colgarse cuando cerca de 1,3 GB se asignan (estoy usando System.GC.GetTotalMemory (falso); para encontrar la cantidad de bienes asignados).

Me sospecha que puede tener memoria fragmentación . Si el objeto es grande (85000 bytes bajo .NET 2.0 CLR si no recuerdo mal, no sé si se ha cambiado o no), el objeto se asigna en un montón especial, montón de objetos grandes (LOH) . GC hace recuperar la memoria utilizada por los objetos inalcanzables en LOH, aún, que no realiza la compactación, en LOH como lo hace con otros montones (Gen0, Gen1, y gen2), debido a rendimiento.

Si con frecuencia asignar y desasignar objetos de gran tamaño, que hará que la LOH fragmentada y a pesar de que tiene más memoria libre en total que lo que necesita, puede que no tenga un espacio de memoria contigua más, por lo tanto, recibirá una excepción OutOfMemory.

Se me ocurren dos soluciones en este momento.

  1. Mover a 64 bits máquina / OS y tomar ventaja de ella :) (el más fácil, pero posiblemente más difícil, así dependiendo de sus limitaciones de recursos)
  2. Si no puede hacer # 1, a continuación, tratar de asignar una gran tirada de memoria primera y utilizarlos (se puede requerir para escribir alguna clase de ayuda para manipular una matriz más pequeña, que de hecho reside en un conjunto más amplio) para evitar la fragmentación . Esto puede ayudar un poco, sin embargo, no puede resolver completamente el problema y puede que tenga que hacer frente a la complejidad.

Otros consejos

Parece que hemos encontrado con LOH (montón de objetos grandes) tema fragmentación.

grande de objetos Montón

CLR interior hacia fuera del montón de objetos grandes Descubierto

Puede comprobar para ver si usted está teniendo problemas de fragmentación LOH utilizando SOS

para un ejemplo de cómo utilizar el SOS para inspeccionar la LOH.

Forzar a una recolección de elementos no siempre es una buena idea (que en realidad puede promover la vida útil de los objetos en algunas situaciones). Si es necesario, se debería utilizar:

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

No es esto gran fragmentación del objeto del montón? Objetos> 85.000 bytes se asignan en el montón de objetos grandes. La GC libera espacio en este montón, pero nunca compacta los objetos restantes. Esto puede resultar en memoria contigua insufficent para asignar correctamente un objeto grande.

Alan.

Si tuviera que especular problema no es realmente que va desde Vector3 [200200200] a un Vector3 [210210210] pero que muy probablemente usted tiene pasos anteriores similares antes de éste:

 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. Tratar sobre la asignación - tal vez duplicando el tamaño cada vez que en lugar de asignar siempre sólo el espacio que necesita. Especialmente si estas matrices se utilizan cada vez con objetos que deben fijar los amortiguadores (es decir, si que tienen vínculos con código nativo)

Así, en lugar de lo anterior, tener 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];

No puede ser que se recogen porque están siendo referenciados en algún lugar que no esperas.

A modo de prueba, trate de cambiar sus referencias a WeakReferences lugar y ver si se soluciona el problema OOM. Si no lo hace, entonces ellos está haciendo referencia en otro lugar.

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

Una vez dicho esto, si que desee que la funcionalidad, ¿por qué no la creó?

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

Una excepción OutOfMemory desencadena un ciclo interno GC automáticamente una vez e intenta la asignación de nuevo antes de lanzar la excepción de hecho a su código. La única forma en que podría tener excepciones OutOfMemory es si usted está sosteniendo referencias a demasiada memoria. Borrar las referencias tan pronto como sea posible mediante la asignación nula.

Parte del problema puede ser que usted está asignando una matriz multidimensional, que está representado como un único bloque contiguo de memoria en el montón de objetos grandes (más detalles aquí ). Esto puede bloquear otras asignaciones, ya que no es un bloque contiguo de uso gratuito, incluso si todavía hay algo de espacio libre en algún lugar, por lo tanto, la OOM.

Trate su asignación como una matriz escalonada - Vector3 [210] [210] [210] - que se extiende alrededor de las matrices de memoria en lugar de como un solo bloque, y ver si eso mejora las cosas

Juan, la creación de objetos> 85000 bytes hará que el objeto terminan en el montón de objetos grandes. El montón de objetos grandes no se compacta, en lugar del espacio libre se reutiliza de nuevo. Esto significa que si se están asignando las matrices más grandes cada vez, puede terminar en situaciones en las que la LOH es fragmentada, de ahí el OOM.

Usted puede verificar esto es el caso, rompiendo con el depurador en el punto de OOM y conseguir un vertedero, entregando el volcado a MS a través de un fallo de conexión ( http://connect.microsoft.com ) sería un gran comienzo.

Lo que puedo asegurar es que el GC va a hacer lo correcto tratar de satisfacer a petición de asignación, esto incluye dando inicio a un GC para limpiar la basura vieja para satisfacer las nuevas solicitudes de asignación.

No sé cuál es la política de reparto de volcados de memoria en Stackoverflow, pero estaría dispuesto a echar un vistazo para entender su problema más.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top