Pregunta

Aunque entiendo las graves consecuencias de jugar con esta función (o al menos eso es lo que creo), no veo por qué se está convirtiendo en una de esas cosas que respetable programadores no use nunca, incluso aquellos que ni siquiera saben de qué se trata.

Digamos que yo estoy desarrollando una aplicación en la que el uso de la memoria varía extremadamente dependiendo de lo que el usuario está haciendo.La aplicación del ciclo de vida se puede dividir en dos etapas principales:la edición y el procesamiento en tiempo real.Durante la etapa de edición, supongamos que miles de millones o incluso billones de objetos son creados;algunos de ellos pequeños y algunos de ellos no, algunos pueden tener finalizadores y algunos no, y supongo que su vida útil puede variar en muy pocos milisegundos hasta largas horas.A continuación, el usuario decide cambiar a tiempo real de la etapa.En este punto, supongamos que el rendimiento juega un papel fundamental, y la menor alteración en el flujo podría traer consecuencias catastróficas.La creación de objetos es reducido al mínimo posible mediante el uso de las piscinas de objetos y tal, pero luego, la GC campanadas inesperadamente y lo tira todo por la borda, y alguien muere.

La pregunta:En este caso, ¿no sería buena idea llamar a la GC.Collect() antes de entrar en la segunda etapa?

Después de todo, estas dos etapas nunca se superponen en el tiempo el uno con el otro y todos la optimización y estadísticas de la GC podría haber reunido sería de poco uso aquí...

Nota:Como algunos de ustedes han señalado, .RED podría no ser la mejor plataforma para una aplicación como esta, pero que está más allá del alcance de esta pregunta.La intención es aclarar si la GC.Collect() llamada puede mejorar una aplicación general del comportamiento/rendimiento o no.Todos estamos de acuerdo en que las circunstancias bajo las cuales se debe hacer una cosa son extremadamente raros, pero, de nuevo, la GC trata de adivinar y lo hace perfectamente bien la mayoría de las veces, pero todavía se trata de adivinar.

Gracias.

¿Fue útil?

Solución

De Rico el Blog de...

Regla #1

No.

Este es realmente el más importante de la regla.Es justo decir que la mayoría de los usos de la GC.Collect() son una mala idea y fui a que en algunos de los detalles en el original de publicación, así que no repetiré todos los que aquí.Así que vamos a pasar a...

Regla #2

Considere la posibilidad de llamar a la GC.Collect() si algunos no recurrentes del suceso que acaba de ocurrir y en este caso, es altamente probable que han causado una gran cantidad de objetos antiguos para morir.

Un ejemplo clásico de esto es que si usted está escribir una aplicación cliente y pantalla muy grande y complicado la forma que tiene una gran cantidad de datos asociados con ella.El usuario acaba de interactuó con esta forma potencialmente la creación de algunos objetos de gran tamaño...cosas como documentos XML, o un gran conjunto de datos o dos.Cuando se cierra el formulario de estos los objetos son muertos, y GC.Collect() va a recuperar la memoria asociada con ellos...

Asi como suena esta situación puede caer en virtud de la Regla #2, usted sabe que hay un momento en el tiempo donde una gran cantidad de objetos antiguos han muerto, y no recurrentes.Sin embargo, no olvide Rico palabras de despedida.

Regla #1 debe trump Regla #2 sin evidencia fuerte.

Medir, medir, medir.

Otros consejos

Si usted llamar a la GC.Collect() en el código de producción que son, esencialmente, declarando que usted sabe más, los autores de la GC.Ese puede ser el caso.Sin embargo, normalmente no, y por lo tanto desanimado.

Entonces, ¿qué sucede cuando usted está usando los objetos COM, como MS Word o MS Excel .NETA?Sin llamar GC.Collect después de la liberación de los objetos COM hemos encontrado que la Palabra o de la aplicación de Excel casos todavía existen.

De hecho, el código que uso es:

Utils.ReleaseCOMObject(objExcel)

' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its 
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process, 
' but one that may be necessary when automating Excel because it is the only way to 
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

Por lo que sería un uso incorrecto de el recolector de basura?Si es así, ¿cómo podemos obtener la Interoperabilidad de los objetos a morir?También si no está destinado a ser utilizado como esta, ¿por qué es el GC's Collect método aún Public?

Así, la GC es una de esas cosas que tengo una relación amor / odio con.Tenemos roto en el pasado a través de VistaDB y blogs sobre ello.Se han arreglado, pero se necesita MUCHO tiempo para conseguir correcciones de ellos en cosas como esta.

La GC es complejo, y una talla única para todos enfoque es muy, muy difícil de sacar algo de este tamaño.MS ha hecho un trabajo bastante bueno de él, pero es posible engañar a la GC a veces.

En general no se debe agregar un Collect a menos que usted sabe que es un hecho que acabes de una tonelada de memoria y se va a ir a un a mediados de crisis de la vida si el GC no limpiarla ahora.

Usted puede arruinar toda la máquina con una serie de malas GC.Collect las declaraciones.La necesidad de recoger declaración casi siempre apunta a un mayor error subyacente.La pérdida de memoria por lo general tiene que ver con las referencias y una falta de entendimiento de cómo funcionan.O el uso de la IDisposable en los objetos de los que no lo necesita y poner un mucho mayor carga en el GC.

Mirar de cerca el % de tiempo dedicado a la GC a través de los contadores de rendimiento del sistema.Si usted ve a su aplicación a través de un 20% o más de su tiempo en la GC que tiene serios objeto de las cuestiones de gestión (o de un uso anormal del patrón).Se desea minimizar el tiempo que el GC pasa porque aumentará la velocidad de su aplicación.

También es importante tener en cuenta que la GC es diferente en los servidores de las estaciones de trabajo.He visto una serie de pequeñas difícil de rastrear problemas con las personas que no pruebas tanto de ellos (o ni siquiera son conscientes de que hay dos de ellos).

Y sólo para ser tan completo en mi respuesta como sea posible, usted debe también probar en Mono si usted está apuntando a que la plataforma así.Ya que es totalmente diferente que la aplicación se puede experimentar totalmente diferentes problemas que MS implementación.

Hay situaciones en las que es útil, pero en general se debe evitar.Se podría comparar con GOTO, o la conducción de un ciclomotor:que hacer cuando usted lo necesita, pero no se lo digas a tus amigos acerca de ello.

Desde mi experiencia, nunca ha sido conveniente hacer un llamado a la GC.Collect() en el código de producción.En la depuración, sí, pero tiene sus ventajas para ayudar a aclarar los posibles fugas de memoria.Supongo que mi razón fundamental es que la GC ha sido escrito y optimizado por los programadores mucho más inteligente, a continuación, yo, y si llego a un punto en el que siento que tengo que llamar a la GC.Collect() es un indicio de que he pasado fuera de ruta en algún lugar.En su situación, no parece que realmente tienen problemas de memoria, sólo que a usted le preocupa lo que la inestabilidad de la colección va a traer a su proceso.Viendo que no va a limpiar objetos, todavía en uso, y que se adapta muy rápidamente a ambos subiendo y bajando las demandas, yo creo que usted no tendrá que preocuparse de ello.

Una de las mayores razones para llamar a la GC.Collect() es cuando sólo han realizado un importante evento que crea un montón de basura, tal como lo que usted describe.Llamar a la GC.Collect() puede ser una buena idea;de lo contrario, la GC no puede entender que era 'una vez' evento.

Por supuesto, usted debe perfil, y ver por ti mismo.

Bueno, obviamente no se debe escribir código con los requisitos en tiempo real en idiomas no en tiempo real de la recolección de basura.

En un caso con etapas bien definidas, no hay ningún problema con la activación de la recolector de basura.Pero este caso es extremadamente raro.El problema es que muchos desarrolladores se va a tratar de utilizar este papel por problemas en una carga-culto de estilo, y añadiendo indiscriminadamente va a causar problemas de rendimiento.

Llamar a la GC.Collect() obliga a CLR para hacer un recorrido de la pila para ver si cada objeto puede ser verdaderamente se libera mediante la comprobación de referencias.Esto va a afectar a la escalabilidad si el número de objetos es alta, y también se ha sabido para activar la recolección de basura demasiado a menudo.Confiar en el CLR y dejar que el recolector de basura de funcionar por sí mismo cuando sea apropiado.

La creación de imágenes en un bucle - incluso si usted llamar a dispose, la memoria no se recupera.Recoger la basura cada vez.Me pasó de 1,7 GB de memoria en mi foto de procesamiento de aplicación a los 24MB y el rendimiento es excelente.

No hay absolutamente el tiempo que usted necesita llamar a la GC.Recopilar.

De hecho, no creo que es una muy mala práctica de llamar a la GC.Recopilar.
Puede haber casos cuando lo necesitamos.Sólo por ejemplo, tengo un formulario que tiene un hilo de rosca, que inturn se abre differnt de las tablas de una base de datos, extrae el contenido en un campo BLOB a un archivo temporal, cifrar el archivo, a continuación, lea el archivo en un binarystream y de nuevo en un campo BLOB en otra tabla.

Toda la operación se lleva un buen montón de memoria, y no es seguro sobre el número de filas y el tamaño de los archivos contenidos en las tablas.

Solía tener OutofMemory Excepción a menudo y pensé que sería sabio para ejecutar periódicamente GC.Recoger basado en una variable de contador.Yo incrementar un contador y cuando un determinado nivel es alcanzado, el GC está llamado a recoger toda la basura que puede haber formado, y para recuperar la memoria perdida debido a imprevistos pérdidas de memoria.

Después de esto, creo que está funcionando bien, al menos no es la excepción!!!
Yo llamo de la siguiente manera:

var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).

Bajo .net, el tiempo requerido para realizar una recolección de basura es mucho más fuertemente relacionada con la cantidad de cosas que no es basura, que para la cantidad de cosas que se.De hecho, a menos que un objeto reemplaza Finalize (ya sea de forma explícita o a través de C# destructor), es el objetivo de un WeakReference, se encuentra en el Montón de Objetos Grandes, o es especial en algunas otras relacionadas con la gc, la única cosa que la identificación de la memoria en la que se sienta como un objeto, es la existencia de una arraigada referencias a ella.De lo contrario, el GC de la operación es análoga a la toma de un edificio, todo lo de valor, y dinamitado el edificio, la construcción de uno nuevo en el sitio de la antigua, y poniendo todos los artículos de valor en ella.El esfuerzo requerido para dinamita el edificio es totalmente independiente de la cantidad de basura dentro de ella.

En consecuencia, llamando GC.Collect es conveniente aumentar la cantidad total de trabajo que el sistema tiene que hacer.Que va a retrasar la aparición de la próxima colección, pero probablemente va a hacer tanto trabajo de inmediato como la próxima colección habría requerido cuando ocurrió;en el momento de la próxima colección se hubiera producido, la cantidad total de tiempo dedicado a la recogida habrá sido aproximadamente el mismo que había GC.Collect no se ha llamado, pero el sistema se han acumulado algunas de basura, provocando que el éxito de la colección de que se requiere más pronto de lo que había GC.Collect no ha llamado.

Las veces que puedo ver GC.Collect realmente son útiles cuando uno necesita para medir el uso de la memoria de código (ya que el uso de la memoria cifras sólo son realmente significativas después de una colección), o el perfil que de varios algoritmos es mejor (llamar a la GC.Collect() antes de ejecutar cada una de las diferentes piezas de código puede ayudar a asegurar una consistente línea de base del estado).Hay un par de casos en los que uno puede conocer las cosas de la GC no, pero a menos que uno está escribiendo un único subproceso programa, no hay manera de que uno puede saber que un GC.Collect llamada con ayuda del hilo de las estructuras de datos de evitar la "crisis de mediana edad" no causar otros hilos' de datos para tener un "mid-las crisis de la vida" que de otro modo habrían sido evitados.

Hemos tenido un problema similar con el recolector de basura no se recoge la basura y liberar memoria.

En nuestro programa, hemos sido procesamiento de algunos modesto tamaño de hojas de cálculo de Excel con OpenXML.Las hojas de cálculo contenida en cualquier lugar de 5 a 10 "hojas" con cerca de 1000 filas de columnas de 14.

El programa en una versión de 32 bits (x86) accidente con un "out of memory error".Nos hicieron llegar para que se ejecute en una versión de 64 bits de medio ambiente, pero queríamos una solución mejor.

Hemos encontrado.

Aquí están algunos simplificado de fragmentos de código de lo que no funcionó y qué no funcionó cuando se trata de una llamada explícita a que el Recolector de elementos no utilizados para liberar memoria de desechar objetos.

Llamar a la GC dentro de la subrutina no funciona.La memoria nunca fue recuperada...

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
End Sub

Moviendo el GC llamar a fuera del ámbito de aplicación de la subrutina, la basura fue recogida y la memoria se libera.

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
End Sub

Espero que esto ayude a otros que se sienten frustrados con el .RED de recolección de basura cuando parece ignorar las llamadas a GC.Collect().

Paul Smith

No hay nada malo con una llamada explícita de una colección.Algunas personas realmente quiero creer que si es un servicio proporcionado por el proveedor, no lo pregunta.Ah, y a todos aquellos que al azar se congela en el peor de los momentos de su aplicación interactiva?La próxima versión va a hacer mejor!

Dejando a un proceso en segundo plano acuerdo con la memoria de la manipulación de los medios no tener que lidiar con nosotros mismos, cierto.Pero esto lógicamente no significa que sea mejor para nosotros no lidiar con nosotros mismos en todas las circunstancias.El GC está optimizado para la mayoría de los casos.Pero esto lógicamente no significa que sea optimizado en todos los casos.

¿Alguna vez has contestado a una pregunta abierta como "cual es el mejor algoritmo de ordenación' con una respuesta definitiva?Si es así, no toque la GC.Para aquellos de ustedes que preguntó por las condiciones, o dio 'en este caso' tipo de respuestas, usted puede proceder a aprender acerca de la GC y cuando lo active.

Tengo que decir, he tenido la aplicación se congela en Chrome y Firefox que frustran el infierno fuera de mí, y aun así, para algunos casos la memoria crece sin trabas -- Si sólo hubieran aprender a llamar al recolector de basura-o me ha dado un botón para que al comenzar a leer el texto de una página que puede golpear y así ser libre de heladas para los próximos 20 minutos.

Creo que tienes razón sobre el escenario, pero no estoy seguro acerca de la API.

Microsoft dice que en tales casos, usted debe añadir la presión de la memoria como una sugerencia para que la GC que pronto debe realizar una colección.

¿Qué tiene de malo?El hecho de que estamos en el segundo consiste en adivinar el recolector de basura y asignador de memoria, que entre ellos tengan una mayor idea acerca de su aplicación real del uso de memoria en tiempo de ejecución que usted.

El deseo de llamar a la GC.Collect() generalmente está tratando de encubrir errores que cometió en alguna otra parte!

Sería mejor si usted encuentra donde usted se olvidó de deshacerse de cosas que no necesitaba más.

Línea inferior, que pueden perfil de la aplicación y ver cómo estas colecciones adicionales que afectan las cosas.Te sugiero que mantenerse alejado de ella, aunque menos que usted va a perfil.El GC está diseñado para cuidar de sí mismo y como el tiempo de ejecución evoluciona, se puede aumentar la eficiencia.Usted no quiere un montón de código que cuelga alrededor que puede simular las obras y no ser capaz de tomar ventaja de estas mejoras.Hay un argumento similar para el uso de foreach en lugar de para, que el ser, que las futuras mejoras de debajo de las mantas pueden ser añadidos a foreach y su código no tiene que cambiar para tomar ventaja.

El .NET Framework en sí nunca fue diseñado para ejecutarse en un entorno en tiempo real.Si usted realmente necesita en tiempo real de procesamiento se utiliza un embebidos en tiempo real idioma que no se basa en .RED o el uso de la .NET Compact Framework que se ejecuta en un dispositivo Windows CE.

Lo peor que se va a hacer es hacer que su programa de congelación para un poco.Así que si eso está bien con usted, hágalo.Normalmente no es necesario para el grueso de cliente o aplicaciones web con la mayoría de la interacción con el usuario.

He encontrado que a veces los programas, con los subprocesos de larga ejecución, o de programas por lotes, obtendrá OutOfMemory excepción, incluso a pesar de que son la eliminación de los objetos correctamente.Yo recuerdo era una línea de negocio de la base de datos de procesamiento de transacciones;la otra era una rutina de indización en un subproceso en segundo plano en un espesor de aplicación de cliente.

En ambos casos, el resultado fue simple:No GC.Recoger, de memoria, de forma coherente;GC.Recopilar, un rendimiento impecable.

Yo lo he probado para resolver los problemas de memoria varias veces, sin éxito.Me sacó.

En resumen, no la pongas en menos que usted esté recibiendo errores.Si usted lo puso y no soluciona el problema de memoria, tomar de ella hacia fuera.Recuerde probar en modo de Lanzamiento y comparar manzanas con manzanas.

La única vez que las cosas pueden ir mal con esto es cuando usted consigue moralista acerca de él.No es un problema de valores;muchos programadores han muerto y se ha ido directamente al cielo con muchos innecesarios GC.Recoge en su código, que deja de ser ellos.

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