c# - sistemas - ¿Cómo evitar la recolección de basura en la aplicación.NET en tiempo real?
servicio de recoleccion de basura pasa (13)
En lugar de crear una nueva instancia de un objeto cada vez que recibe un mensaje, ¿por qué no reutiliza los objetos que ya se han utilizado? De esta forma no lucharás contra el recolector de basura y tu memoria de pila no se fragmentará. **
Para cada tipo de mensaje, puede crear un grupo para contener las instancias que no están en uso. Cada vez que recibe un mensaje de red, observa el tipo de mensaje, saca una instancia en espera del grupo apropiado y aplica su lógica comercial. Después de eso, vuelve a colocar esa instancia del objeto de mensaje en su grupo.
Lo más probable es que desee "cargar de forma diferida" su grupo con instancias para que su código se pueda escalar fácilmente. Por lo tanto, su clase de grupo necesitará detectar cuándo se ha retirado una instancia nula y llenarla antes de distribuirla. Luego, cuando el código de llamada lo vuelve a poner en el grupo, es una instancia real.
** "La agrupación de objetos es un patrón que permite reutilizar los objetos en lugar de asignarlos y desasignarlos, lo que ayuda a evitar la fragmentación del montón y las costosas compactaciones GC".
Estoy escribiendo una aplicación financiera C # que recibe mensajes de la red, los traduce a diferentes objetos según el tipo de mensaje y finalmente aplica la lógica de negocios de la aplicación en ellos.
El punto es que después de aplicar la lógica de negocios, estoy muy seguro de que nunca necesitaré esta instancia nuevamente. En lugar de esperar a que el recolector de basura los libere, me gustaría explícitamente "eliminarlos".
¿Hay una mejor manera de hacerlo en C #, debería usar un conjunto de objetos para reutilizar siempre el mismo conjunto de instancias o hay una mejor estrategia?
El objetivo es evitar que la recolección de basura use cualquier CPU durante un proceso de tiempo crítico.
En teoría, el GC no debería funcionar si su CPU tiene una carga pesada o si realmente es necesario. Pero si es necesario, puede guardar todos sus objetos en la memoria, quizás una instancia singleton, y nunca limpiarlos a menos que esté listo. Esa es probablemente la única forma de garantizar cuando se ejecuta el GC.
Forzar un GC.Collect () generalmente es una mala idea, dejar el GC para hacer lo que mejor sabe hacer. Parece que la mejor solución sería usar un grupo de objetos que pueda cultivar si es necesario. He utilizado este patrón con éxito.
De esta forma evitará no solo la recolección de basura sino también el costo de asignación regular.
Finalmente, ¿estás seguro de que el GC te está causando un problema? Probablemente deberías medirlo y probarlo antes de implementar cualquier solución de ahorro de rendimiento: ¡podrías estar causando un trabajo innecesario!
Golpea usted mismo: use un conjunto de objetos y reutilice esos objetos. La semántica de las llamadas a esos objetos debería ocultarse detrás de una fachada de fábrica. Necesitarás hacer crecer el grupo de una manera predefinida. Tal vez el doble de tamaño cada vez que llega al límite: un algoritmo de alta concentración de agua o un porcentaje fijo. Realmente le recomiendo encarecidamente que no llame a GC.Collect ().
Cuando la carga en su grupo sea lo suficientemente baja, puede reducir el grupo y eso eventualmente desencadenará una recolección de basura; deje que el CLR se preocupe por ello.
Intentar adivinar el recolector de basura generalmente es una muy mala idea. En Windows, el recolector de basura es generacional y se puede confiar en que es bastante eficiente. Hay algunas excepciones notables a esta regla general: la más común es que la ocurrencia de un evento de una sola vez que usted conozca de hecho habrá causado la muerte de muchos objetos antiguos, una vez que los objetos se hayan promovido a Gen2 (el más longevo) tienden a pasar el rato.
En el caso que mencione, parecerá que está generando una cantidad de objetos efímeros; estos generarán colecciones Gen0. Estos ocurren con relativa frecuencia de todos modos, y son los más eficientes. Podría evitarlos teniendo un grupo de objetos reutilizables, si lo prefiere, pero es mejor cerciorarse con certeza si el GC es un problema de rendimiento antes de realizar dicha acción: el perfilador CLR es la herramienta para hacerlo.
Cabe señalar que el recolector de basura es diferente en diferentes marcos .NET en el marco compacto (que se ejecuta en la Xbox 360 y en las plataformas móviles) es un GC no generacional y, como tal, debe ser mucho más cuidadoso con lo que basura que genera tu programa.
Obtenga una buena comprensión y sienta cómo se comporta el recolector de basura, y comprenderá por qué no se recomienda lo que está pensando aquí. a menos que realmente le guste el CLR para pasar tiempo reorganizando mucho los objetos en la memoria.
Puede tener una cantidad limitada de instancias de cada tipo en un grupo, y reutilizar lo ya hecho con las instancias. El tamaño de la agrupación dependerá de la cantidad de mensajes que procesará.
Si es absolutamente crítico en el tiempo, entonces debe usar una plataforma determinista como C / C ++. Incluso al llamar a GC.Collect () generará ciclos de CPU.
Su pregunta comienza con la sugerencia de que desea guardar memoria pero deshacerse de los objetos. Esta es una optimización de espacio crítico. Debe decidir lo que realmente quiere porque el GC es mejor para optimizar esta situación que un ser humano.
Mire aquí: http://msdn.microsoft.com/en-us/library/bb384202.aspx
Puede decirle al recolector de basura que está haciendo algo crítico en este momento, y tratará de ser amable con usted.
Por lo que parece, parece que estás hablando de una finalización determinista (destructores en C ++), que no existe en C #. Lo más parecido que encontrará en C # es el patrón Desechable. Básicamente, implementas la interfaz IDisposable .
El patrón básico es este:
public class MyClass: IDisposable
{
private bool _disposed;
public void Dispose()
{
Dispose( true );
GC.SuppressFinalize( this );
}
protected virtual void Dispose( bool disposing )
{
if( _disposed )
return;
if( disposing )
{
// Dispose managed resources here
}
_disposed = true;
}
}
¿Qué tan intensiva es la aplicación? Escribí una aplicación que captura 3 tarjetas de sonido (Managed DirectX, 44.1KHz, Stereo, 16 bits), en bloques de 8KB, y envía 2 de las 3 transmisiones a otra computadora a través de TCP / IP. La interfaz de usuario representa un medidor de nivel de audio y un título / artista de desplazamiento (suave) para cada uno de los 3 canales. Esto funciona en PC con XP, 1.8GHz, 512MB, etc. La aplicación usa aproximadamente el 5% de la CPU.
Me mantuve alejado de llamar manualmente a los métodos de GC. Pero tuve que sintonizar algunas cosas que fueron un desperdicio. Utilicé el perfilador Ant de RedGate para perfeccionar las partes derrochadoras. Una herramienta increíble!
Quería usar un conjunto de matrices de bytes preasignados, pero el ensamblaje DX administrado asigna los almacenamientos intermedios de bytes internamente, luego los devuelve a la aplicación. Resultó que no era necesario.
No los elimine de inmediato. Llamar al recolector de basura por cada objeto es una mala idea. Normalmente, realmente no quieres jugar con el recolector de basura, e incluso los procesos críticos en el tiempo son solo condiciones de carrera a la espera de que sucedan si son tan sensibles.
Pero si sabe que tendrá períodos de carga ocupados y de carga ligera para su aplicación, puede intentar con un GC.Collect () más general cuando alcance un período de luz para alentar la limpieza antes del próximo período ocupado.
"El objetivo es evitar que la recolección de basura use cualquier CPU durante un proceso crítico en el tiempo"
P: Si por tiempo crítico, ¿quiere decir que está escuchando alguna pieza de hardware esotérica, y no puede permitirse perder la interrupción?
R: Si es así, entonces C # no es el idioma que se debe usar, usted quiere Assembler, C o C ++ para eso.
P: Si por tiempo crítico, ¿se refiere a que hay muchos mensajes en la tubería y no quiere que el recolector de basura reduzca la velocidad?
R: Si es así, te estás preocupando innecesariamente. Por el sonido de las cosas, sus objetos tienen una vida muy corta, esto significa que el recolector de basura los reciclará de manera muy eficiente, sin ningún retraso aparente en el rendimiento.
Sin embargo, la única manera de saberlo con certeza es probarlo, configurarlo para que se ejecute durante la noche procesando un flujo constante de mensajes de prueba. Me sorprenderá si tus estadísticas de rendimiento pueden detectar cuando el GC entra en acción (e incluso si puedes) detectarlo, estaré aún más sorprendido si realmente importa).