Pregunta

Estoy escribiendo una aplicación financiera en C# que recibe mensajes de la red, los traduce en diferentes objetos según el tipo de mensaje y finalmente les aplica la lógica empresarial de la aplicación.

El punto es que una vez aplicada la lógica empresarial, estoy muy seguro de que nunca volveré a necesitar esta instancia.En lugar de esperar a que el recolector de basura los libere, me gustaría "eliminarlos" explícitamente.

¿Existe una mejor manera de hacerlo en C#? ¿Debería usar un grupo de objetos para reutilizar siempre el mismo conjunto de instancias o existe una estrategia mejor?

El objetivo es evitar que la recolección de basura utilice cualquier CPU durante un proceso de tiempo crítico.

¿Fue útil?

Solución

No los elimines de inmediato.Llamar al recolector de basura para cada objeto es una mala idea.normalmente tu en realidad No quiero meterme con el recolector de basura en absoluto, e incluso los procesos críticos en el tiempo son solo condiciones de carrera esperando suceder si son tan sensibles.

Pero si sabe que tendrá períodos de carga ocupada versus períodos livianos para su aplicación, puede probar un GC.Collect() más general cuando llegue a un período liviano para fomentar la limpieza antes del próximo período ocupado.

Otros consejos

Mira aquí: http://msdn.microsoft.com/en-us/library/bb384202.aspx

Puedes decirle al recolector de basura que estás haciendo algo crítico en este momento y él intentará ser amable contigo.

Te golpeas a ti mismo: usa un conjunto de objetos y reutiliza esos objetos.La semántica de las llamadas a esos objetos debería ocultarse detrás de la fachada de una fábrica.Necesitará hacer crecer el grupo de alguna manera predefinida.Quizás duplique el tamaño cada vez que alcance el límite: un algoritmo de nivel alto o un porcentaje fijo.Realmente le recomiendo encarecidamente que no llame a GC.Collect().

Cuando la carga en su grupo sea lo suficientemente baja, podría reducir el grupo y eso eventualmente desencadenará una recolección de basura; deje que CLR se preocupe por eso.

Intentar adivinar al recolector de basura es generalmente una muy mala idea.En Windows, el recolector de basura es uno generacional y se puede confiar en que es bastante eficiente.Hay algunas excepciones notables a esta regla general: la más común es la ocurrencia de un evento único que usted sabe con certeza habrá causado la muerte de muchos objetos antiguos, una vez que los objetos se promueven a Gen2 (el de mayor duración). tienden a andar por ahí.

En el caso que menciona, suena como si estuviera generando una serie de objetos de corta duración; estos darán como resultado colecciones Gen0.De todos modos, estos ocurren con relativa frecuencia y son los más eficientes.Puede evitarlos si tiene un grupo de objetos reutilizable, si lo prefiere, pero es mejor asegurarse con certeza si GC es un problema de rendimiento antes de tomar tal acción; el generador de perfiles 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 Xbox 360 y en plataformas móviles) es un GC no generacional y, como tal, debe tener mucho más cuidado con lo que basura que genera tu programa.

Forzar un GC.Collect() es generalmente una mala idea, deje que el GC haga lo que mejor sabe hacer.Parece que la mejor solución sería utilizar un grupo de objetos que puedas hacer crecer si es necesario; he utilizado este patrón con éxito.

De esta manera evitará no sólo 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 medir y probar esto antes de implementar cualquier solución que ahorre rendimiento: ¡es posible que te estés causando un trabajo innecesario!

"El objetivo es evitar la recolección de basura para utilizar cualquier CPU durante un proceso crítico en el tiempo"

P: Si por tiempo crítico, ¿te refieres a que estás escuchando alguna pieza esotérica de hardware y no puedes darte el lujo de perder la interrupción?

A: Si es así, entonces C# no es el lenguaje a usar; para eso querrás Assembler, C o C++.

P: Si por tiempo crítico, ¿te refieres a que hay muchos mensajes en la tubería y no quieres que el recolector de basura ralentice el proceso?

A: Si es así, te estás preocupando innecesariamente.Por lo que parece, tus 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 forma de saberlo con certeza es probarlo, configurarlo para que se ejecute durante la noche procesando un flujo constante de mensajes de prueba. Me sorprendería si sus estadísticas de rendimiento pueden detectar cuándo se activa el GC (e incluso si puede). detectarlo, me sorprendería aún más si realmente importara).

Comprenda y sienta bien cómo se comporta el recolector de basura y comprenderá por qué no se recomienda lo que está pensando aquí.a menos que realmente te guste que CLR dedique tiempo a reorganizar objetos en la memoria mucho.

¿Qué tan intensiva es la aplicación?Escribí una aplicación que captura 3 tarjetas de sonido (DirectX administrado, 44,1 KHz, estéreo, 16 bits), en bloques de 8 KB, y envía 2 de las 3 transmisiones a otra computadora a través de TCP/IP.La interfaz de usuario muestra un medidor de nivel de audio y un título/artista de desplazamiento (suave) para cada uno de los 3 canales.Esto se ejecuta en PC con XP, 1,8 GHz, 512 MB, etc.La aplicación utiliza aproximadamente el 5% de la CPU.

Me mantuve alejado de llamar manualmente a los métodos de GC.Pero tuve que ajustar algunas cosas que fueron un desperdicio.Utilicé el perfilador Ant de RedGate para centrarme en las porciones derrochadoras.¡Una herramienta increíble!

Quería usar un grupo de matrices de bytes preasignadas, pero el ensamblaje DX administrado asigna buffers de bytes internamente y luego los devuelve a la aplicación.Resultó que no era necesario.

Si el tiempo es absolutamente crítico, entonces debería utilizar una plataforma determinista como C/C++.Incluso llamar a GC.Collect() generará ciclos de CPU.

Su pregunta comienza con la sugerencia de que desea ahorrar memoria pero deshacerse de los objetos.Esta es una optimización de espacio crítico.Debes decidir qué es lo que realmente quieres porque el GC optimiza mejor esta situación que un humano.

Por lo que parece, parece que estás hablando de finalización determinista (destructores en C++), que no existe en C#.Lo más parecido que encontrarás en C# es el patrón Desechable.Básicamente implementas el Desechable interfaz.

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;
    }
}

Podría tener una cantidad limitada de instancias de cada tipo en un grupo y reutilizar las instancias ya hechas.El tamaño del grupo dependerá de la cantidad de mensajes que procesará.

En lugar de crear una nueva instancia de un objeto cada vez que recibe un mensaje, ¿por qué no reutiliza objetos que ya se han utilizado?De esta manera no lucharás contra el recolector de basura y tu memoria dinámica 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, extrae una instancia en espera del grupo apropiado y aplica su lógica de negocios.Después de eso, vuelves a colocar esa instancia del objeto de mensaje en su grupo.

Lo más probable es que desees "cargar de forma diferida" tu grupo con instancias para que tu código se escale fácilmente.Por lo tanto, su clase de grupo deberá detectar cuándo se ha extraído una instancia nula y completarla antes de entregarla.Luego, cuando el código de llamada lo devuelve al 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 de GC".

http://geekswithblogs.net/robp/archive/2008/08/07/speedy-c-part-2-optimizing-memory-allocations---pooling-and.aspx

En teoría, el GC no debería ejecutarse si su CPU está bajo una carga pesada o a menos que realmente lo necesite.Pero si es necesario, es posible que desee mantener todos sus objetos en la memoria, tal vez una instancia única, y nunca limpiarlos a menos que esté listo.Probablemente esa sea la única forma de garantizar cuándo se ejecuta el GC.

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