Parte de lo que ocurre en el GC es que los objetos en la memoria son generacional, de manera que las primeras generaciones se recogen con más frecuencia que otros. Esto ayuda a ahorrar rendimiento al no intentar recopilar objetos de larga duración todo el tiempo.
Teniendo esto en cuenta, pueden ocurrir dos cosas cuando llamas al GC.Collect()
. La primera es que termina gastando más tiempo haciendo colecciones. Esto se debe a que las colecciones normales de fondo seguirán apareciendo además de su manual GC.Collect(). La segunda es que se aferrará a la memoria más larga, porque forzó algunas cosas en una generación de orden superior que no tenía que ir allí. En otras palabras, usar GC.Collect() es casi siempre una mala idea.
En algunos casos, el recolector de basura no siempre funciona bien. Uno de estos es el gran montón de objetos. Esta es una generación especial para objetos de un tamaño mayor (80,000 bytes, IIRC, pero eso podría ser viejo ahora).Esta generación casi nunca se recoge y casi nunca compacta. Eso significa que con el tiempo puede terminar con muchos agujeros importantes en la memoria que no se liberarán. La memoria física no se usa realmente y está disponible para otros procesos, pero todavía consume espacio de direcciones dentro de su proceso, de los cuales está limitado a 2 GB de forma predeterminada.
Esta es una fuente muy común para las excepciones OutOfMemory — en realidad no está usando esa cantidad de memoria, pero tiene todo este espacio de direcciones ocupado por agujeros en el montón de objetos grandes. Con mucho, la forma más común de que esto suceda se agrega a cadenas grandes o documentos. Probablemente este no sea usted, porque en este escenario, ninguna cantidad de llamadas a GC.Collect() acompañará al LOH, pero en su caso sí parece ayudar. Sin embargo, esta es la fuente de la gran mayoría de las excepciones de OutOfMemory que he visto.
Otro lugar donde el recolector de basura no siempre funciona bien es cuando ciertas cosas hacen que los objetos permanezcan enraizados. Un ejemplo es que los controladores de eventos pueden evitar la recopilación de un objeto. Una forma de evitar esto es asegurarse de que cada operación +=
para suscribir un evento tenga una operación correspondiente -=
para anular su suscripción. Pero, de nuevo, es poco probable que un GC.Collect() ayude aquí: el objeto aún está rooteado en algún lugar, por lo que no se puede recopilar.
Afortunadamente, esto le brinda una vía de investigación para resolver su problema subyacente que causa la necesidad de utilizar GC.Collect() en primer lugar. Pero si no es, por supuesto, es mejor tener un programa que funcione que un programa que falla. En cualquier lugar que use GC.Collect(), me aseguraré de que el código esté bien documentado con el motivo por el que lo necesita (obtiene excepciones sin) y los pasos exactos y los datos necesarios para reproducirlo de manera confiable para que los futuros programadores que Es posible que desee eliminar esto, puede saber con seguridad cuándo es seguro hacerlo.
+ ve Vota por pensamientos muy perspicaces –
En realidad, llamar a GC.Collect() puede que no sea tan malo (como inicialmente pensé) especialmente leyendo este artículo de Jeffery Richter http://msdn.microsoft.com/en-us/magazine/ bb985011.aspx "ya que su aplicación sabe más acerca de su comportamiento que el tiempo de ejecución, podría ayudarlo forzando explícitamente algunas colecciones". Aunque todavía tengo curiosidad por saber por qué GC.Collect ayuda a resolver OOM cuando el objeto está en LOH, donde GC.Collect no tiene control. –
@palmsnow, también sentía curiosidad por eso. Después de buscar mucho he encontrado la respuesta aquí: http://stackoverflow.com/questions/10016541/garbage-collection-not-happening-even-when-needed – SiberianGuy