¿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?
-
01-10-2019 - |
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.
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 ??em>. .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
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).