example - Eliminación de objetos de C#.NET
c# implement dispose correctly (7)
¿Todavía existe en la pila después de la llamada?
La semántica es importante aquí. Usted preguntó si todavía existe en la pila después de la llamada al método. La respuesta es "no". Fue eliminado de la pila. Pero esa no es la historia final. El objeto aún existe, ya no está rooteado. No será destruido o recolectado hasta que se ejecute el GC. Pero en este momento ya no es tu problema. El GC es mucho mejor para decidir cuándo recolectar algo que tú o yo.
¿Tengo que configurarlo para que GC lo note más rápido?
Casi nunca hay una buena razón para hacer eso, de todos modos. El único momento que ayuda es si tiene un método de ejecución muy larga y un objeto que haya finalizado antes, que de lo contrario no saldrá del alcance hasta el final del método. Incluso entonces, establecerlo como nulo solo ayudará en el raro caso en que el GC decida correr durante el método. Pero en ese caso probablemente estés haciendo algo diferente también.
Debería ser fácil. Digamos que tengo el siguiente código:
void Method()
{
AnotherMethod(new MyClass());
}
void AnotherMethod(MyClass obj)
{
Console.WriteLine(obj.ToString());
}
Si llamo a "Método ()", ¿qué sucede con el objeto MyClass que se creó en el proceso? ¿Todavía existe en la pila después de la llamada, aunque nada lo esté usando? ¿O se elimina de inmediato?
¿Tengo que configurarlo para que GC lo note más rápido?
Si llamo a "Método ()", ¿qué ocurre con el objeto MyClass que se creó en el proceso?
Se crea en el montón de GC. Luego, se coloca una referencia a su ubicación en el montón en la pila. Entonces ocurre la llamada a AnotherMethod. Luego se llama al método ToString del objeto y se imprime el resultado. Luego, regresa AnotherMethod.
¿Todavía existe en la pila después de la llamada, aunque nada lo esté usando?
Tu pregunta es ambigua Por "la llamada" ¿te refieres a la llamada a Method u AnotherMethod? Hace una diferencia porque en este punto, si la memoria de montón es un candidato para la recolección de basura depende de si compiló con optimizaciones activadas o desactivadas. Voy a cambiar ligeramente tu programa para ilustrar la diferencia. Supongamos que tienes:
void Method()
{
AnotherMethod(new MyClass());
Console.WriteLine("Hello world");
}
Con las optimizaciones desactivadas, a veces generamos código que sería así:
void Method()
{
var temp = new MyClass();
AnotherMethod(temp);
Console.WriteLine("Hello world");
}
En la versión no optimizada, el tiempo de ejecución realmente elegirá tratar el objeto como no recuperable hasta que el Método regrese, después de la WriteLine. En la versión optimizada, el tiempo de ejecución puede elegir tratar el objeto como de colección tan pronto como vuelva AnotherMethod, antes de la WriteLine.
El motivo de la diferencia es que hacer que el tiempo de vida del objeto sea más predecible durante las sesiones de depuración a menudo ayuda a las personas a comprender sus programas.
¿O se elimina de inmediato?
Nada se recoge de inmediato; el recolector de basura se ejecuta cuando parece que debería funcionar. Si necesita algún recurso como un identificador de archivo para limpiarse inmediatamente cuando haya terminado con él, utilice un bloque "usar". De lo contrario, deje que el recolector de basura decida cuándo recolectar memoria.
¿Tengo que configurarlo para que GC lo note más rápido?
¿Tienes que establecer qué anular? ¿Qué variable tenías en mente?
De todos modos, no tienes que hacer nada para que el recolector de basura funcione. Funciona solo por sí mismo sin que lo solicite.
Creo que estás pensando demasiado en este problema. Deje que el recolector de basura haga su trabajo y no se preocupe por eso. Si tiene un problema real con la memoria que no se recopila de manera oportuna, entonces muéstrenos un código que ilustre ese problema; de lo contrario, simplemente relájate y aprende a amar la recuperación automática de almacenamiento.
El GC realiza un seguimiento de los objetos a los que todavía se puede hacer referencia más adelante en el código. Luego, a intervalos, comprueba si todavía hay objetos vivos que posiblemente no se puedan referenciar más adelante en el código, y los limpia.
La mecánica de esto es algo compleja, y cuando estas colecciones sucedan depende de una variedad de factores. El GC está diseñado para hacer estas colecciones en el momento más óptimo (que puede establecer) y así, aunque es posible obligarlo a hacer una colección, casi siempre es una mala idea.
Establecer la variable a nulo tendrá muy poco efecto general sobre la rapidez con la que se trata el objeto. Si bien, en algunos casos de esquina pequeña, puede ser beneficioso, no vale la pena ensuciar tu código con asignaciones redundantes que no afectarán el rendimiento de tus códigos y solo dañarán la legibilidad.
El GC está diseñado para ser lo más efectivo posible sin necesidad de pensarlo. Para ser sincero, lo único que realmente debes tener en cuenta es tener cuidado al asignar objetos realmente grandes que permanecerán vivos durante mucho tiempo, y eso es bastante raro en mi experiencia.
En C #, el nuevo MyClass () tiene un alcance solo para vivir dentro de Method () mientras está activo. Una vez que AnotherMethod () se termina de ejecutar, queda fuera de alcance y se desloca. Luego permanece en el montón hasta que el GC ejecuta su ciclo de recopilación y lo identifica como un bloque de memoria sin referencia. Por lo tanto, todavía está "vivo" en el montón, pero es inaccesible.
En realidad, la instancia se declarará en el montón, pero eche un vistazo al artículo de Eric Lipper, The Stack es un detalle de implementación .
En cualquier caso, debido a que no habrá más referencias a la instancia después de que se ejecute la función, el recolector de basura la eliminará (o, más exactamente, se puede eliminar) en algún punto indefinido en el futuro. En cuanto a exactamente cuando sucede eso, no está definido, pero también (esencialmente) no necesita preocuparse por eso; el GC tiene algoritmos complicados que lo ayudan a determinar qué y cuándo recolectar.
Hasta donde yo sé, el objeto solo es válido dentro del contexto de su método. Después de que se ejecuta el método "Método ()", se agrega a la cola de eliminación.
Una vez que finaliza la llamada al Método, su objeto MyClass
está activo, pero no hay referencias desde un valor rooteado. Entonces vivirá hasta la próxima vez que el GC se ejecute donde será recolectado y recuperado la memoria.
Realmente no hay nada que pueda hacer para acelerar este proceso que no sea forzar un GC. Sin embargo, esta es probablemente una mala idea. El GC está diseñado para limpiar tales objetos y cualquier intento que hagas para hacerlo más rápido probablemente resulte en un proceso más lento en general. También encontrará que un GC, al limpiar correctamente los objetos administrados, puede que no reduzca realmente la memoria de su sistema. Esto se debe a que el GC lo conserva para su uso futuro. Es un sistema muy complejo que generalmente es mejor dejarlo en sus propios dispositivos.