vtortola.NET Logo
Desechable o no desechable

Desechable o no desechable

por vtortola viernes, 11 de julio de 2008

La interfaz IDisposable nos provee del método .Dispose() que utilizamos para liberar los recursos que esta usando ese objeto, pero dicho método... no deja de ser un simple método ;) Solo hace falta hacer una pequeña prueba para darse cuenta:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Desechable test = new Desechable();
   6:            
   7:          test.Dispose();
   8:   
   9:          Console.WriteLine(test.Cadena??"Muerto"); // Muestra: Vivo!
  10:          Console.ReadKey(true);
  11:      }
  12:  }
  13:   
  14:  class Desechable : IDisposable
  15:  {
  16:      public String Cadena = "Vivo!";
  17:   
  18:      public void Dispose()
  19:      {
  20:   
  21:      }
  22:  }

Ok ok... un poco más complejo:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          Desechable test = new Desechable();
   6:          WeakReference wr = new WeakReference(test.Tabla.Columns[0]);
   7:   
   8:          test.Dispose();
   9:          test = null;
  10:   
  11:          Console.WriteLine(((DataColumn)wr.Target).ColumnName); // Muestra "Columna"
  12:          Console.ReadKey(true);
  13:      }
  14:  }
  15:   
  16:  class Desechable : IDisposable
  17:  {
  18:      public DataTable Tabla = new DataTable();
  19:   
  20:      public Desechable()
  21:      {
  22:          Tabla.Columns.Add(new DataColumn("Columna"));
  23:      }
  24:   
  25:      public void Dispose()
  26:      {
  27:          Tabla.Dispose();
  28:      }
  29:  }

El resultado cambia si en la línea 10 hacemos un GC.Collect() ;D

Como vemos, el único que puede liberar memoria en el .NET Framework es el Garbage Collector, por lo que el método .Dispose() no libera memoria in libera nada, solo nos sirve para asegurar que el objeto que estamos desechando ha cerrado correctamente todos sus recursos y podemos olvidarnos de él, ya se encargará el GC de liberar la memoria cuando lo crea necesario.

Entonces, implementar la interfaz IDisposable no hace nuestros objetos "destruibles" bajo demanda, ni setear todos los campos a null en Dispose no va a hacer que sea recolectado más deprisa, ni no hacerlo va a evitar que sea recolectado, ni debemos des-subscribir los eventos...

Por lo tanto, debemos implementar el patrón IDisposable en una clase siempre que:

  • Nuestra clase deriva de una clase que lo implementa.
  • Nuestra clase esta compuesta de otras clases que lo implementan.
  • Hagamos uso de recursos no administrados.

Para todo lo demás... mastercard confia en el GC :D

Un tema que causa controversia en este aspecto es... ¿que pasa con los delegados? ¿Como el estar subscrito a delegados afecta a la recolección de memoria? Bien, el estar subscrito a un delegado de una clase, no afecta en su recolección:

   1:  class Program
   2:  {
   3:      static void Main(string[] args)
   4:      {
   5:          MiClase test = new MiClase();
   6:          WeakReference wr = new WeakReference(test);
   7:          
   8:          test.MiEvento += new EventHandler(test_MiEvento);
   9:   
  10:          test = null;
  11:          GC.Collect();
  12:   
  13:          Console.WriteLine(wr.IsAlive ? "Vivo" : "Muerto"); // Muestra "Muerto"
  14:          Console.ReadKey(true);
  15:      }
  16:   
  17:      static void test_MiEvento(object sender, EventArgs e)
  18:      {
  19:          throw new NotImplementedException();
  20:      }
  21:  }
  22:   
  23:  class MiClase
  24:  {
  25:      public event EventHandler MiEvento;
  26:  }

Pero al revés, es decir, que una clase este subscrita a uno de nuestros delegados... si provoca que el objeto no pueda ser recolectado:

   1:  class Program
   2:  {
   3:      static event EventHandler Evento;
   4:      static void Main(string[] args)
   5:      {
   6:          MiClase test = new MiClase();
   7:          WeakReference wr = new WeakReference(test);
   8:   
   9:          Evento += test.Manejador_Evento;
  10:   
  11:          test = null;
  12:          GC.Collect();
  13:   
  14:          Console.WriteLine(wr.IsAlive ? "Vivo" : "Muerto"); // Muestra "Vivo"
  15:          Console.WriteLine(Evento.GetInvocationList().Length); // Muestra 1
  16:          Console.ReadKey(true);
  17:      }
  18:  }
  19:   
  20:  class MiClase
  21:  {
  22:      public void Manejador_Evento(object sender, EventArgs e)
  23:      {
  24:          throw new NotImplementedException();
  25:      }
  26:  }

Y ojo, que los delegados son muy comodos para ejecutar muchos métodos de una pasada (por ejemplo podríamos tener una serie de objetos subscritos a un delegado y cada vez que invocaramos a este se ejecutaria ese método en todos los objetos), pero como veis pueden causar un memory leak; aunque en ese caso poco podemos hacer desde el método Dispose ya que es otra clase la que ha de desuscribirse.

Saludos desde el frio Dublin donde el Verano es una broma de mal gusto.

Actualmente calificado 4.9 por 7 persona(s)

  • Currently 4,857143/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , ,

.NET 2.0 | C# 2.0

Related posts

Comentarios

julio 11. 2008 15:45

trackback

Trackback from Pensando en asíncrono

Desechable o no desechable

Pensando en asíncrono

julio 11. 2008 15:46

trackback

Trackback from vtortola

Desechable o no desechable

vtortola

Comments are closed

Powered by BlogEngine.NET 1.1.1.8
This theme is a variation of Mads Kristensen by Valeriano Tórtola

Valeriano Tórtola

Personal Ver perfil
E-mail Enviar correo
LinkedIn LinkedIn
Fotos Fotos
MCPD

Publicidad

Posts recientes

Disclaimer

Las opiniones mostradas aqui son mis opniones y no representan el punto de vista de mi empresa en ninguna forma.

Creative Commons License

Esta obra está bajo una licencia de Creative Commons

Locations of visitors to this page

© Copyright 2010

Sign in

Calendario

<<  marzo 2010  >>
lumamijuvido
22232425262728
1234567
891011121314
15161718192021
22232425262728
2930311234

Ver en calendario extendido