¿Hay una práctica común cómo hacer que la memoria de desagüe en función del colector de basura más fácil en .NET?

StackOverflow https://stackoverflow.com/questions/2714811

Pregunta

he estado pensando si hay una manera de cómo acelerar la liberación de memoria en .NET. Estoy creando un juego en el .NET (código sólo gestionado) que no se necesita gráficos significativos, pero todavía me gustaría escribir correctamente con el fin de no perder rendimiento a cambio de nada.

Por ejemplo ¿es útil para asignar valor nulo a los objetos que no son ya necesarios? Veo esto en unas pocas muestras a través de Internet.

¿Fue útil?

Solución

  

¿es útil para asignar valor nulo a los objetos que no son ya necesarios?

Generalmente, no. La mayoría de las muestras podrás ver en línea que hacen esto son las personas que vinieron a .Net de Visual Basic 6, donde se trataba de una práctica común. En .Net, es menos útil. Si usted tiene un método muy larga duración, que podría dejar que el recolector de basura y buscar el objeto un poco más temprano - pero si su método es que el tiempo que tienen otros problemas.

En lugar de ello, en .Net se debe construir métodos cortos y definir las variables lo más tarde posible en los bloques de alcance más pequeñas posibles. Usa el curso de la vida "natural" de la variable tal como se determina por alcance, pero mantener ese corto tiempo de vida natural.

debe no a hacer su propia recolección de basura, según lo sugerido por al menos otra respuesta aquí. En realidad, esto puede hacer que las cosas más lenta . .NET utiliza un recolector de basura generacional. Al forzar una recolección de basura, que podría recoger el objeto de destino (que tampoco podría - no hay garantías con la recolección de basura). Sin embargo, es probable que también se fuerza un montón de otros objetos que no se puede cobrar aún para ser almacenados en una generación de orden superior, lo que hace que sean más difíciles de recoger en el futuro. Así que no hacerlo.

Otros consejos

Usted no debe preocuparse demasiado y no optimiza de forma prematura. gestión de memoria en .NET es automático y muy eficiente. Si usted empieza a 'Optimizar' lo que necesita saber exactamente lo que está haciendo o puede que reducir la velocidad.

Así que terminar de jugar primero, y luego, si se utiliza demasiado lento un generador de perfiles para encontrar el problema. Lo más probable es que no será un problema de memoria.

La mayoría de los objetos gráficos relacionados en .NET (imagen y sus descendientes, gráficos, pluma, pincel, etc.) implementan IDisposable. Si vas a utilizar un objeto para una operación específica, a continuación, otra vez no, utilice el siguiente patrón:

using(var g = Graphics.FromBitmap(bmp))
{
    //Do some stuff with the graphics object
}

Hacerlo de esta manera se asegurará de todos los recursos no administrados conseguirán liberado cuando caen fuera del ámbito.

Me encontrar objetos en un .NET de las cosas que más influye en el rendimiento de la asignación. Para evitar esto utilizo el patrón de la fábrica donde Reciclo objetos que he utilizado. Aquí es simple implementación genérica:

internal class ListFactory<T> 
    where T: IRecyclable, new()
{
    private List<T> _internalList;
    private int _pointer;

    public ListFactory()
    {
        _internalList = new List<T>();
        _pointer = 0;
    }

    public void Clear()
    {
            _pointer = 0;
    }

    public int Count
    {
        get
        {
            return _pointer;
        }
    }

    public List<T> InnerList
    {
        get
        {
            return _internalList;
        }
    }

    //Either return T form the list or add a new one
    //Clear T when it is being reused
    public T Create()
    {
        T t;

        //If the pointer is less than the object count then return a recycled object
        //Else return a new object 
        if (_pointer < _internalList.Count )
        {
            t = _internalList[_pointer];
            t.Recycle();
        }
        else
        {
            t = new T();
            _internalList.Add(t);
        }
        _pointer ++;
        return t;
    }
}

En mi línea de enrutamiento algoritmo, tengo que mantener constantemente muchos valores como RouteNode que implementa la interfaz siguiente:

public interface IRecyclable
{
    void Recycle();
}

Estos conseguir constantemente crea y se destruye. Para reciclar estos objetos, crear una nueva fábrica:

nodeFactory = new ListFactory<RouteNode>();

Cuando se necesita un objeto, llame al método create:

RouteNode start = nodeFactory.Create();
RouteNode goal = nodeFactory.Create();

Cuando haya terminado con los objetos de la lista, borrar la lista. El puntero se restablece al comienzo de la lista, pero los objetos mismos no son destruidos. De hecho, el método de reciclaje sólo se invoca cuando el objeto se recupera de nuevo. (Es posible que desee hacer esto antes si tiene otras referencias a objetos, ver los comentarios más abajo)

Esta es una aplicación bastante ingenuo, pero es un lugar para empezar.

Puede ser útil en algunos casos a objetos establece en NULL que ya no son necesarios. A menudo es inútil o contraproducente, pero no siempre. Cuatro situaciones principales en que puede ser de ayuda:

campos
  • Objetos que contienen declarados como "WithEvents" en vb.net debe aplicar IDisposable, y deben anulado esos campos en el método Dispose. No sé por qué vb.net no incluye una buena manera de anulación automáticamente los campos WithEvents, pero puesto que no deberán ser borrados manualmente.
  • Si una variable local contiene una referencia a un objeto que de hecho nunca se volverá a utilizar, pero puede ser un tiempo antes de que el código llega a un punto en el que el compilador sabe la variable no conseguirá utilizado, la limpieza la variable puede permitir que la referencia sea liberado pronto.
  • Si en algún momento una matriz que es grande o ha existido por algún tiempo se sabe que es inútil, y si las referencias a algunos objetos asignados recientemente se almacenan en ella, la limpieza de esas referencias antes de destruir todo sobreviviente las referencias a la matriz pueden permitir que los objetos recién creados para ser liberados mucho antes de lo que lo sería.
  • Si un objeto tiene una rutina de finalizar y está en la cola de la finalización, todos los objetos referenciados directa o indirectamente por él, serán exentos de recolección de basura. En consecuencia, los objetos finalizables no deben hacer referencia a todo lo que no será necesario para la finalización.

        
  • Para hacer esto (y he tenido que hacer esto con frecuentes> asignaciones 50MB), llamada:

            myObj = null;
            GC.Collect();
            GC.WaitForPendingFinalizers();
    

    Me he dado cuenta de que el consumo de memoria de la aplicación va a continuación, disminuir en gran medida. En teoría, no debería tener que hacer esto. Sin embargo, en la práctica, y con ventanas de 32 bits OS podría obtener 2 bloques contiguos de> 300 MB libres en un momento dado, y que tiene que el espacio ocupado por un montón de pequeñas asignaciones o una serie de unos grandes puede significar que otras asignaciones grandes se fallar innecesariamente. Las carreras recolector de basura en el fondo cuando se puede, pero si es absolutamente necesario hacer grandes asignaciones en este momento, ese conjunto de líneas de ayuda para hacer posible que para mí.

    EDIT:. De lo que he puesto en los comentarios, por los downvoters

    Si usted lee la totalidad post acerca de la recolección de basura por Rico Mariani , se le nota que las grandes, poco frecuentes, las asignaciones de memoria no predecibles caen en escenario # 2. Para whit:

      

    Regla # 2

         

    Considere llamar GC.Collect () si algunos   no recurrentes evento que acaba de ocurrir   y este evento es muy probable que   han causado una gran cantidad de objetos antiguos a   troquel.

         

    Un ejemplo clásico de esto es que si estás   escribir una aplicación cliente y se   mostrar una muy grande y complicado   formulario que tiene un montón de datos asociados   con eso. Su usuario tiene solo   interactuado con esta forma potencialmente   la creación de algunos objetos grandes cosas ...   como documentos XML, o un gran conjunto de datos   o dos. Cuando se cierra el formulario éstos   los objetos están muertos y por lo GC.Collect ()   reclamará la memoria asociada   con ellos.

         

    Ahora qué iba a sugerir esto como una   posible momento de llamar al colector?   Es decir, mi consejo es algo habitual   así como "el colector se ajusta automáticamente de modo   No te metas con ella."¿Por qué el cambio   de la actitud usted puede pedir?

         

    Bueno, aquí es una situación en la   tendencia del colector [sic] para tratar de predecir   el futuro basado en el pasado es probable   a no tener éxito.

    Si haces grandes asignaciones en su juego, tendrá que tener cuidado acerca de cómo se maneja la memoria. Las obras del colector de basura en la predicción basada en sucesos pasados, y grandes bloques de memoria en una máquina de 32 bits puede ser devastador para las asignaciones futuras si no se maneja adecuadamente. Si no lo ha hecho, no asuma automáticamente que estoy equivocado; si lo ha hecho, daría la bienvenida a una explicación de cómo hacerlo correctamente (es decir, la forma de la memoria de desfragmentación para asegurarse de que siempre se puede 50-100mb asignación de memoria en un momento dado).

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