Be the lord of objects: Garbage Collector

B

En lenguajes como C++ tenemos que preocuparnos constantemente acerca del manejo de la memoria. El uso de punteros y controlar la memoria es necesario cuando desarrollamos aplicaciones en C++, si no hacemos un buen uso de memoria podríamos incurrir en “memory leak .Afortunadamente, para los C# lovers no tenemos esa clase de traumas. Tenemos un garbage collector que nos evita preocuparnos un poco o casi totalmente de el manejo de la memoria. Sin embargo, cuando estamos desarrollando aplicaciones, cruzamos el ciertos límites y tenemos que lidiar con conexiones de base de datos o manejo de archivos. No es algo que vamos a usar siempre pero cuando sea necesario, es bueno saberlo.

Las tres claves que te ayudarán a ser un amo del ciclo de vida de tus objetos son los siguientes:

 

  • Manejo de recursos
  • Implementar y usar IDisposable
  • Garbage collector

 

Garbage Collector(Recolector de Basura)

Para entender cómo funciona debemos comprender que el uso de memoria en ejecución tiene dos caminos, heap y stack.  Empecemos por el stack, es responsable darle seguimiento a lo que se está ejecutando en nuestro código o que ha sido ejecutado. MIentras que el heap es el encargado de dar seguimiento a nuestros objetos.

 

Ambos son similares, pero existen diferencias:

Heap Stack
Mantiene la información de los objetos Mantiene el orden en que se ejecutan los objetos.
No existe restricción para acceder a lo almacenado Existe restricciones, solo se puede acceder al primer elemento
No da seguimiento a la ejecución Da seguimiento a la ejecución
Tiene que preocuparse por el garbage collector Se limpia al finalizar el método. No tiene preocupaciones.

 


Nota:

Es una simplificación de cómo funciona la memoria usualmente, hay procesos que están en ambas partes de la memoria.


 

El recolector de basura o garbage collector, funciona con un algoritmo compacto, que determina cuál ítem en el heap de nuestra memoria está siendo referenciado, por un otro.

Lo cual puede ser un campo estático, una variable local. Cuando encuentra objetos con esta relación los marca, coloca juntos y empieza a liberar espacio de los demás objetos. Cuando realiza esto tiene que estar seguro que el estado no está cambiando, porque mientras está realizando esto el proceso de selección y compactar los objetos estas congelados.

 

Esta es una parte, que desconocía antes de investigar a profundidad. Ya que impacta directamente el rendimiento de la aplicación. En términos simples, el garbage collector se encarga de eliminar elementos en el heap que no van a necesitar y asegurarse de que objetos queden vivos en memoria que no están en uso.

 

Manejo de Otros Recursos

Manejar objetos como strings, números y otros tipos son manejados por el garbage collector, pero tenemos otros variables en la ecuación como conexiones de red, manejo de archivos, que podrían darnos errores. Es por esto que C# soporta el uso de finalization. Esto nos permite limpiar el garbage collector.

 

Sin embargo, no es lo mismo que un destructor como en C++. Para llamar al finalizador, requerimos agregar ciertas sintaxis.

 

Convirtiendo en Código

 

Dentro del finalizador, puedes limpiar otros recursos, para estar seguro que toda la memoria es libre.Por ejemplo, si trabajas con un archivo en C# tendrás que liberar todos los recursos que no se manejado por el  garbage collectorr antes de borrar el archivo.

Con los tipos stream hago una salvedad cada vez que abrimos uno, debemos insertarlo dentro de un using, así cuando el scope del using termina se invoca de forma automática el método Dispose().

La desventaja que tenemos  al finalizar un objeto es que en realidad no lo estamos destruyendo sino alargando su ciclo de vida e incluso almacenando en una pila de objetos “finalizados”, lo que retarda el trabajo del garbage collector. Pero esto no es para nada fabuloso y mucho menos lo ideal, es por esto que contamos con la interfaz IDisposable.

 

Uso de Dispose para liberar recursos

 

Pero qué ocurriría si la excepción pasa antes de nuestro stream.Dispose()? Para asegurarnos que los recursos siempre van a estar limpios, debemos implementar nuestro IDisposable, dentro de una sentencia try/finally. En este caso si enrollamos nuestro código dentro de un using,  el compilador lo va a entender como un try/finally.

 

Finalmente, hagamos la implementación de IDisposable y Finalizer

Hagamos un pequeño análisis de los puntos mas importantes:

El método Dispose con el argumento booleano hace todo el trabajo, este método válida si ha sido llamado Dispose explicitamente o si ha sido por el finalizer.

Si el finalizer llama Dispose, no hace nada porque el objeto Stream tambien implementa el Dispose, es decir ya se hará el llamado del garbage collector por debajo sin ncesidad de mas intervensión.

El método estandar del Dispose llama GC.SuppressFinalize(this)  Para estar seguro que el objeto ha sido removido de la lista de finalización de la cual el garbage collector está haciendo un seguimiento.  La instancia ya se ha limpiado después de sí misma, por lo que no es necesario que el  garbage collector llame al finalizador.

La diferencia mas importante entre el finalizador y el IDisposable, es que el finalizador es llamado por el garbage collector mientras que el Dispose puede ser llamado desde tu codigo.

 

Conclusiones

Tengo tres advertencias finales:

Cuidado con los objetos grandes en el heap, siempre que tenga sentido, es deseable reutilizarlos y matenerlos referenciados durante la vida del proceso.

Presta atención a  la concatenación de strings en bucle, estas si se hacen muy grandes terminarían en constantes colecciones de basuras y el muy posible consumo 100% del CPU.

Cuidado con las referencias a otros objetos que se puedan mantener. Cachear objetos indirectamente puede ser una forma de provocar un memory leak en aplicaciones .NET

Hasta la proxima amigos!

Acerca del Autor

leslie.ramirez

Soy estudiante Ing. De tecnología de la Información y comunicación, tecnólogo superior en Desarrollo de Software. Me considero una persona innovadora y creativa, disfruto aprender cosas nuevas y desarrollar aplicaciones.

Entradas recientes

Categorías