Liberación de memoria en código manejado (¿Dispose, Finalize, Object = Nothing, GC.Collect?)

Para quienes venimos del desarrollo utilizando Visual Basic 6.0, una de las primeras cosas que nos enseñan al empezar a utilizar código manejado (framework), es que ya no es necesario liberar la memoria porque “.net lo hace por ti”. Esta última parte entre comillas, además de ser incorrecta en su definición, es muy engañosa/confusa para quién es nuevo utilizando el framework.

¿Por qué está incorrecta en su definición?

De partida, el decir que .net lo hace es tan amplio que pierde el enfoque y no queda claro quiénes son los actores involucrados.


El actor principal es el garbage collector (GC). Éste está encargado de reservar la memoria desde el sistema operativo (grandes pedazos de memoria) y administrar los requerimientos de memoria de nuestra aplicación (pequeños pedazos de memoria). Esta administración comprende las tareas de asignar la memoria que es requerida por nuestra aplicación, por ejemplo las variables, para posteriormente reclamarla una vez que se ha dejado de utilizar. Para más información, ver el siguiente post sobre el manejo de memoria.

¿Por qué es engañosa/confusa para desarrolladores novatos en código manejado?

Si el problema se mira desde 10.000 metros de altura y si todos los componentes que se usan están correctamente programados, podemos decir que el GC si libera la memoria por ti.


Veamos las sutilezas que hacen que lo anterior pueda no cumplirse.


El GC es no-determinístico. ¿Qué significa esto? Significa que éste limpia la memoria cuando ÉL estima que es necesario y no cuanto TÚ quieres que lo haga; su ejecución no está determinada por ti, ni se ejecuta siguiendo un patrón detectable desde código. Sí lo hace siguiendo un algoritmo de optimización/adiestramiento interno, pero no es fácilmente detectable por uno como desarrollador. Además, al ser un algoritmo que se va adiestrando con el tiempo, su frecuencia de ejecución no es siempre repetible o predecible.


Entonces, si nos vamos a 10.000 metros de altura y para un tiempo T >> 0, podemos decir que la memoria será reclamada (liberada) por el GC, un poco más tarde de lo que se haría en VB 6.0, pero será reclamada.


Por otro lado, el GC no libera la memoria conocida como no manejada, es decir, la memora que él no administró. ¿Quién libera esta memoria? La respuesta tiene matices, primero el desarrollador, pero si éste no lo hace, alguien debe hacerlo.


Cuando se programan componentes que manejan recursos no manejados, el programador DEBE implementar el [patronDispose], que incluye la interfaz [IDisposable]. Esto debe hacerlo sí o sí.


Programadores expertos podrán argumentar que no es necesario implementar el [patronDispose] o que se puede implementar a medias (ver sección de los problemas más abajo referente al mito del finalizador). Esto es cierto, pero dependerá del control que ellos tengan sobre el uso de los tipos (clases) generados por ellos. Desde el momento en que ellos no controlen quién usará sus tipos, será entonces obligación hacerlo ya que es un estándar esperable.


Yo, como desarrollador, debiera ser el responsable de liberar la memoria no manejada llamando al método Dispose una vez que he dejado de utilizar el objeto de ese tipo. Esto, a diferencia del funcionamiento del GC, liberará inmediatamente la memoria no manejada utilizada por el tipo.

¿Qué sucede si el desarrollador no llama a Dispose?

Entonces dependerá de varios factores el que afecte o no a mi aplicación. Veamos algunos de ellos.


Si quién desarrolló el tipo que estoy utilizando implementó el [patronDispose] de forma correcta, los recursos manejados serán liberados cuando se ejecute el finalizador. Éste, de la misma forma que el GC, es no-determinístico.


Al no ser determinístico, la liberación de los recursos no manejados podrá hacerse tan tarde que podríamos encontrarnos con [OOM] o quedarnos sin conexiones a SQL Server (esto yo lo he visto en algunos casos donde he trabajado).


Tristemente, si el código no implementó Finalize porque el desarrollador novato no supo que había que hacerlo o porque el experto confió en que quién lo iba a usar llamaría a Dispose, definitivamente nos encontraremos con [OOM].

¿Dónde empiezan los problemas?

Uno de ellos se da porque rara vez un programador implementa el finalizador. Esto se debe a la existencia de un mito/costo asociado a éste. Es totalmente cierto que tener un tipo que implementa el finalizador tiene un sobrecosto en rendimiento comparado a un tipo que no lo implementa. Ahora, es muy cierto también que si se implementa el [patronDispose] de forma correcta, existe una línea de código en la función Dispose que quita parte de ese sobrecosto. Veamos el código de ésta:






public void Dispose()


{


    Dispose(true);

    GC.SuppressFinalize(this);

}

 

Sin entrar en demasiados detalles, el sobrecosto mencionado de tener un tipo que implementa Finalize se debe a que cada vez que se crea una instancia de éste tipo, este nuevo objeto se agrega a una cola especial de procesamiento. Bueno, esta función SuppressFinalize saca la instancia de la cola. Entonces, al final, el único sobrecosto está en agregar y sacar una instancia de la cola. No se cuantificar este costo, pero puedo asegurar que es mucho menor a los problemas producto de memoria no liberada. Se debe entender que una vez que se ha hecho Dispose de los recursos no manejados, ya no hay necesidad de llamar a Finalize porque no hay nada que finalizar.


Por eso es importante que el desarrollador llame al método Dispose, ya que además de garantizar la correcta liberación de recursos no manejados, también se produce esta optimización. Ese es otro de los problemas. El desarrollador no sabe que tiene que llamar a Dispose porque le dijeron que .net libera la memoria automáticamente.


El último de los problemas se da por que el desarrollador escucha o lee [recmalas] o poco precisas y decide usar el mismo código que estaba tan bien justificado (es en sentido irónico) en este otro sitio. Esto se refiere al uso de GC.Collect.

¿Y si llamo a GC.Collect?

Llamar a GC.Collect no tiene ningún efecto positivo; más aún, los efectos negativos producto de la ejecución de ésta podrían impactar severamente el rendimiento y consumo de recursos. Esto tiene que quedar claro ¡ya!


Jamás debe llamarse a GC.Collect. Existen excepciones contadas con menos dedos que los que tiene una mano, en las cuales el hacerlo podría (potencialmente) tener beneficios, pero esas no están dentro de las labores de desarrollo tradicional. Para el trabajo día a día, GC.Collect no está dentro de las funciones a utilizar.

Si no puedo recolectar la memoria, igualo los objetos a nothing/null

El igualar los objetos a nulo tiene, en la práctica, un impacto mínimo en la liberación de memoria. MSDN define esto como:






In Visual Basic .NET, setting an object to Nothing marks the object for garbage collection, but the object is not immediately destroyed.

 

Es correcto. Si se iguala un objeto a nulo, lo único que se está logrando es marcándolo para que sea liberado, la próxima vez que se ejecute el GC, algo que ya sabemos que ocurre de forma no determinística y en una frecuencia no conocida por los desarrolladores. Entonces, ¿qué gano haciéndolo?


Existen, al igual que el llamado a GC.Collect, contadas ocasiones donde asignar nulo a variables puede ayudar, pero todo dependerá de las probabilidades.


Supongamos que estamos en una función donde se han creado objetos que consumen mucha memoria (datasets, colecciones, hashtables, etc.), y que en alguna de las líneas que vienen más abajo, se hará una llamada a una función que demorará bastante (Web Service, SQL Server, etc.). Si llegase a ocurrir una recolección de memoria mientras se ejecuta esta función larga, todos estos objetos grandes envejecerán (pasarán de generación en el GC) y no serán liberados ya que aún se están “usando”.


Ahí es donde se puede hacer la diferencia. Si yo sé que no se usarán más adelante en la función, entonces puedo igualarlos a nulo y en la eventualidad que se produzca una recolección, estos serán efectivamente recolectados por el GC (no envejecerán) y la memoria será liberada.


¿Qué otras opciones existen donde valga la pena hacerlo?


Yo al menos no conozco ninguna otra, lo que por cierto no significa que no haya.

¿Y si igualo a nulo y llamo a GC.Collect?

Nuevamente, no se debe llamar a GC.Collect salvo contadísimas excepciones, las que no hemos discutido aquí. Si tú has vivido una situación donde hayas podido demostrar fehacientemente que el llamado a GC.Collect produjo un resultado positivo, te ruego compartirla.


Ahora, si tienes otro punto de vista o situación vivida que difiera de lo que acabamos de ver, también te ruego compartirla.


Patrick.

125 Replies to “Liberación de memoria en código manejado (¿Dispose, Finalize, Object = Nothing, GC.Collect?)”

  1. Buen artículo,pero…sigo teniendo una duda.
    Como programador, debería de usar el dispose de los objetos que creo.
    try
    {
    SqlConnection oConn = …
    {
    catch…
    finally
    {
    oConn.Close();
    oConn.Dispose();
    }

    Saludos. Sergio.

  2. Sergio,

    cuando dices “usar” y “objetos que creo” ¿te refieres a implementar Dispose en tipos definidos por ti o en llamar a dispose de instancias de tipos creadas?

    Para los primeros, si vas a manejar recursos no manejados, si debes implementar IDisposable, aunque los recursos no manejados los maneje algun tipo que tu estes manejando. Ejemplo: Si tengo una clase que tiene una propiedad del tipo de conexión a base de datos, tu clase debe implementar Dispose y éste debe llamar al Dispose de la conexión.

    Para el segundo caso, que es parecido al ejemplo que posteaste ahí, tienes que garantizar que se llame Dispose, ya sea usando un using o try/finally.

    Con esto basta. Dispose llama a close internamente.

    try
    {
    SqlConnection oConn = …
    {
    catch…
    finally
    {
    oConn.Dispose();
    }

    Saludos,
    Patrick

  3. en el ultimo comentario respecto al codigo de dispose, indicas que al llamar a Dispose internamente tambien se llama a close (esto refiriendome a un código que se conecta a una BD).

    Entonces que diferencias hay al usar close() y dispose()? o cuando usar uno de ellos o en que casos?

    atte.

  4. Max,

    Excelente pregunta. Dispose en algunos casos implementados hace algo similar a close, sin embargo, no debes basarte solo en eso. Te cuento.

    En la teoría (no refiriéndome a objetos de conexión a BD sino que a reglas generales), Close permite liberar algunos recursos, pero deja el objeto en un estado sobre el cual se pueden seguir ejecutando acciones como Abrir nuevamente la conexión.

    Siguiendo la teoría, si se utiliza Dispose, se entiende que el objeto no será utilizado nuevamente, y cualquier llamada a algún método de este, como tratar de abrirlo nuevamente, no debiera tener éxito y una excepción debiera lanzarse.

    Si te animas, en este caso hay un ejemplo de una mala implementación de Dispose en Sharepoint que lleva a problemas en Webparts de usuario. Te aviso que el post está muy denso y enredado.

    http://msmvps.com/blogs/pmackay/archive/2007/03/11/sharepoint1.aspx

    Saludos,
    Patrick

  5. Como estan.

    Super adecuada la explicacion. Sobre todo que la ejecucion del GC se da en algun momento del tiempo no determinado, y que este libera las porciones de memoria que no estan referenciadas por ningun objeto de algun contexto. ( lo que se hace al hacer un objeto igual a nothing.)

    Pero tengo una pregunta:
    Para las entidades de negocio que transportan valores entre capas (un Entity), se justifica el desgaste para el programador de ponerlas a implemetar IDisposable?

    Quedo atento a sus comentarios, Gracias.

  6. Tengo una aplicacion en silvelight en el cual creo diferentes controles, traté de liberar memoria eliminando los objetos, no se veia la memoria lierada en el IE7, hasta que usé el GC.Collect().

  7. Diego,

    si las entidades tienen solo tipos básicos, entendiendose como básico tipos como strings, ints, booleans, etc., no es necesario y sería una perdida de tiempo. Preguntate lo siguiente. Si la entidad implementara Dispose, ¿qué liberarías cuando alguien llame a dispose?

    Por otra parte, si tu entidad tiene algun campo que sea un dataset o un stream, debieras implementar IDisposable, y en el método dispose, llamar al dispose del dataset y al close del stream.

    Saludos,

    Patrick

  8. Buenas,

    Me ha encantado el artículo, una vez estuve buscando información sobre este mismo tema y desgraciadamente no te encontré, hoy me lo han pasado y me ha abierto el apetito; ¿Podrías pasarme algún enlace con mas información sobre este tema? Yo buscaré también por mi cuenta pero quizás tengas algo que valga la pena por ahí… 😉

    Un saludo y muchas gracias.

  9. Ruben,

    estos links tienen una explicación de cómo funciona el garbage collector y otro sobre cómo implementar dispose correctamente.

    http://msdn.microsoft.com/es-cl/magazine/bb985010(en-us).aspx

    http://msdn.microsoft.com/es-cl/magazine/bb985011(en-us).aspx

    http://www.bluebytesoftware.com/blog/PermaLink.aspx?guid=88e62cdf-5919-4ac7-bc33-20c06ae539ae

    Te comento que este último está para leerlo bien despierto. No lo dejes como lectura de noche….. aunque realmente los otros dos tampoco….

    Saludos,

    Patrick

  10. Muchas gracias por el articulo. Aunque llevo tiempo programando a nivel profesional en C++ y Java, aún soy novato con .net y he caído en el error de leer donde no debía.

    Tenía un problema de memoria con un programa que estoy realizando y realmente usar GC.Collect no ha resultado ser una buena opción, mi proceso comenzaba a consumir memoria, poco a poco, hasta colapsar el sistema. Uno de los errores que comentí parece ser que no liberé bien los recursoso de un socket y por otro lado el trabajo con XML de forma integrá no resultó ser tampoco muy recomendable así que lo he sustituido por listas de XmlElemnts que luego he limpiado a mando como tu recomiendas.

    Tras esto, eliminé el uso del GC.Collect y de momento se ha estabilizado en unos 14,76 Mb. Antes sobrepasaba los 200 Mb antes de caer.

    Lo dicho muchas gracias y habrá que tener cuidado con lo que dejamos en mandos del GC.

  11. excelentes palabras. Lo mejor que se puede hacer con el garbage collector es dejarlo trabajar tranquilo…. y preocuparse de liberar los recursos no administrados…..

    Saludos y gracias por tus palabras

  12. Genial, desde su publicación hace dos años, este artículo continua estando vigente al másimo.
    Gracias a él, un novato como yo, he podido concretar por qué se partía mi programa con Native error 0xc0000005.
    Es una función que graba los datos de un form en la .sdf, tanto el form lo cerraba con close() y llamaba a otra instancia limpia, la conexión la cerraba tras grabar los datos también con close() tras unos minutos de uso partía sin razón aparente.
    GRACIAS EN MAYÚSCULAS

  13. pmackay:

    Primero darte las gracias por esto, ya q no toda la gente se da el tiempo para explicar con tanta buena voluntad.

    te cuento… tengo una aplicacion en .net con c# y la parte grafica esta implementada en flash, estamos ademas cargando .mht en webbrowser, el problema mas grande es que llamando al metodo dispose y asignando null a los objetos, solo consigo bajarle al uso de memoria, pero el uso de la memoria virtual sube, sube y no para de subir hasta que se cae el programa. e usado detodo, hasta el GC.collect() y solo consigo bajarle lo comentado… la memoria virtual se me escapa…

    espero una ayudita de tu parte…

    de antemano muchas gracias.

    Felipe B.

  14. MIRA AUN NO UTILIZO Marshal.ReleaseComObject(objeto) PARA HACER PRUEBAS PERO RESPECTO A TU PREGUNTA TE PUEDO COMENTAR QUE EL PROYECTO ES LOCAL (PC AUTOSERVICIO PARA IMPRIMIR INFORMACION QUE ESTA DENTRO DEL PROYECTO EN FORMATO .MHT), Y AL REALIZARLO SIN IMPLEMENTAR FLASH, NO EXISTE NINGUN PROBLEMA, EL PROBLEMA ES FLASH.

    SALUDOS

  15. hola.

    e estado todos estos dias haciendo pruebas y mi conclusion es q el objeto axShockwaveFlash de flash cada vez que lo llamo de una pagina a otra se aloja en la memoria virtual y el uso de memoria casi a la par y utilizando el close, dispose gc.collect() no baja nada… estoy tratando de utilizar Marshal.ReleaseComObject(objeto) y nose si lo estoy utilizando mal o que, pero no logro bajarle a la virtual y al parecer no estoy eliminado el objeto.

    me tiene preocupado este tema.

    espero puedas ayudarme y gracias otra vez.

    saludos

  16. mmmm, en estos casos, te recomiendo bajar la ultima versión del componente que estas usando…..

    si el problema persiste, ver en los foros de Adobe…. con un poco de suerte, podría estar ahí la respuesta (o al menos el consuelo de que no eres el único)…

    Finalmente, si te animas a tomar un dump de la memoria del proceso, puedo revisarlo y ver si hay algo por ahí……

    saludos…

  17. Solo queria contarte que consegui solucionarlo… el metodo para solucionarlo es el siguiente,el problema es q el flash genera los controles de los botones cada vez que se crea un form… la forma era no crear el new objeto flash, sino que pasar los controles por parametros… eso.

    saludos y gracias.

  18. Hola a tod@s,
    pues he creado una aplicación que llena de manera dinámica un panel en un form, lo llena de controles, le asigna datagrids, ejecuta consultas con muchos registros…
    (Todo esto ocurre desde un punto del menú de la aplicacion)

    Una vez he terminado y quiero generar de nuevo informacion sobre ese panel (he hecho click en otra opcion del menú), descargo el panel y los datatables usados para llenarlos nuevamente.

    Si no llamo a Dispose() de determinados elementos (datatable y datagrid básicamente), y posteriormente hago una llamada a GC.Collect(), la memoria no es liberada y va aumentando cada ve más.

    Haciendo estas llamadas la memoria se mantiene estable.

    ue opinais?

  19. Hola a todos. He hecho varias aplicaciones en vb 2005 y en la mayoria usan entre 30 y 40 Mb de memoria. utilizo me.dispose() siempre al cerrar los forms que abro pero siempre queda algo cargado (entre 2 5 Mb). lo que no utilizo es el GC, recien me entero de eso. Hay alguna solucion rapida para mi problema? Desde ya muchas gracias a todos. Saludos.

  20. Hola a todos. He hecho varias aplicaciones en vb 2005 y en la mayoria usan entre 30 y 40 Mb de memoria. utilizo me.dispose() siempre al cerrar los forms que abro pero siempre queda algo cargado (entre 2 5 Mb). lo que no utilizo es el GC, recien me entero de eso. Hay alguna solucion rapida para mi problema? Desde ya muchas gracias a todos. Saludos.

  21. Buenas Tardes, te hago una consulta, si yo tengo una clase desarrollada por mi en la cual utilizo una conexion a bd, es aquí en donde debo implementar la interface idisposable, para tener disponible el metodo dispose, en el cual llamare al dispose del objeto conexión, verdad?, hasta aqui creo que es asi, ahora, cuando llame al metodo miclase.dispose, estoy liberando el recurso conexión, pero el objeto miclase, no es borrado fisicamente de la memoria, solo logicamente al implementar miclase = nothing, y el GC se encargara de eliminarlo posteriormente. es así el funcionamiento, o estoy errado? Muchas gracias. Saludos.

  22. Un articulo muy interesante y practico ya que hasta ahora no liberaba nada de memoria!!

    Sin embargo tengo una pregunta, si tengo una clase con propiedades “simples” como Integer, String, List Of… tengo que implementar el método Dispose??
    Tiene algún sentido igualar por ejemplo una lista a nothing en la funcion dispose?

  23. Nessy00,

    si tienes una clase con campos y ninguno de estos campos utiliza recursos no manejados, no es necesario implementar dispose. De los tipos simples como los que mandaste, ninguno de esos utiliza recursos no manejados.

    No hay necesidad de igualar nada a nothing en código manejado.

    Patrick

  24. Tengo una aplicación en .net 2008 c# el problema es que aunque tengo el implementado el método dispose en los ancestros de todas mis formas al ejecutar la aplicación por cada ventana que abre reserva memoria y no la libera al cerrar las ventanas, en ocasiones se keda la memoria “bloqueada” aunk ya se haya cerrado la aplicación!!! que me recomiendas??

  25. Mague, nada tienes que hacer. La memoria se libera cuando el garbage collector la reclame. Implementando dispose como hiciste ayuda al proceso de limpieza, pero esto lo notarás sólo cuando ocurra una recolección.

  26. Tengo la siguiente parte de código aplicacion:
    cConectarExcel excel = new cConectarExcel(Arch);
    DataSet ds = excel.TraerDataSetExcel(“select * from [Hoja1$]”, “Tabla1”);
    int i = 1;
    foreach (DataRow dr in ds.Tables[“Tabla1”].Rows){
    GenerarCC generarCC = new GenerarCC();
    generarCC.NumAutorizacion = dr[1].ToString();
    generarCC.NumFactura = dr[2].ToString();
    generarCC.NumNitCi = dr[3].ToString();
    generarCC.FechaTransaccion = dr[4].ToString();
    generarCC.MontoTransaccion = dr[5].ToString();
    generarCC.LlaveDosificacion = dr[6].ToString();
    cc = generarCC.TraerCodigoControl();
    excel.InsertarExcel(“insert into [Hoja1$] (Generado) values (‘” + cc + “‘)”);
    }

    En este ejemplo recupero un dataset con mas de 5000 registros, en el bucle voy creando cada vez el objeto (por supuesto asigando memoria), coloque la creación del objeto fuera del bucle y se van solapando la asiganación de los valores, como podría implementar la liberación de memoria?

  27. No estoy de acuero con lo que dices sobre “Si se iguala un objeto a nulo, lo único que se está logrando es marcándolo para que sea liberado”.

    Como puede igualarse un objeto a null? eso es imposible. Cuando se iguala una variable a null lo que en realidad se esta haciendo es igualar la ‘referencia’ al objeto a null en el stack, pero no se iguala el propio objeto a null en el heap.

    Que sucede si existe otra variable referencia a ese objeto, o en otras palabras, que pasa si otra variable (stak) hace referencia a objeto (heap)? entonces el objeto tendria 2 referencias. Al anular una referencia ‘igualandola a null’ queda la otra referencia y entonces el GC no la destruye por que hay una variable que puede acceder al objeto. El GC solo considera basura los objetos a los que no se puede acceder, esa es ‘su filosofia’, es un ‘recolector de basura’. Por lo tanto el concepto de ‘marcar el objeto para liberarlo’ como tu dices no existe; no existe tal ‘marca’. El GC solo recoje basura y los objetos en el heap se convierten en basura automaticaticamente cuando no existen referencias hacia ellos.

  28. Eduard,

    Lo que tu mencionas se llama ROOTS en el Garbage Collector. Mientras haya algún ROOT, o alguien que está siendo apuntado por un ROOT en cualquier nivel apuntando a un objeto, éste no será liberado, tal como mencionas tú. Mientras sea ‘alcanzable’, no se libera.

    Respecto de los dos primeros párrafos, las apreciaciones son correctas. Efectivamente no existe nada como ‘marcarlo para ser liberado’, sino que lo que se hace es eliminar uno de los posibles ROOTS, o referencia de algo apuntando por algún ROOT en cualquier novel.

    Compartiendo el hecho de haber un error en el texto, también debes comprender que a veces no puedes colocar todos los detalles porque podrías no lograr el efecto y confundirías al lector. Sé que podemos divergir también en éste punto, pero espero que se entienda lo que trato de decir.

    saludos.

  29. he comprobado que llamando al GC.Collect() se liberan los objetos inmediatamente variables, arreglos, etc. en los que se puede usar dispose lo uso y me ha dado buen resultado el GC.Collect()

  30. Buenas. Interesante artículo. Lo he leído como 3 veces, pero no sé si será por la hora o qué, pero todavía no comprendo cuál es la técnica que debería utilizar para liberar memoria.

    Primero, a qué se le llama “recursos no manejados”, o sea, cómo sé que tengo un recurso no manejado en mi código.

    Estoy muy interesado al respecto, porque por ejemplo tengo un form que utiliza un controller/presenter que yo programé, y me gustaría saber si cuando el form se destruye, las listas, variables e implementaciones de otras clases dentro de mi controller/presenter también se libera, me explico? Entonces, no sé si implementar IDispose, pero si lo hago, qué debo meter dentro de Dispose? Igualar todas mis implementaciones de clases y referencias a null?

    Estoy muy perdido al respecto, y realmente te agradecería una respuesta.

    Saludos

  31. Hola. Muy interesante el artículo, te felicito. Comparto tú opinión respecto al GarbageCollect pero recientemente tuve que utilizarlo con resultados positivos.

    Tengo una función que utiliza el XtraGrid de DevExpress y que me permite imprimir el grid seleccionado. Resultado que manejo grandes cantidades de información y cuando hacía una exportación a Excel mi aplicación utilizaba más de 900 MB de memoria. Una vez finalizaba, no se liberaba esta memoria y si volvía a ejecutar la función me daba error por falta de memoria.

    Utilizando using y GC.collect() pude liberar los recursos y ahora ya no tengo este problema.

    Ni modo, soy una excepción… 😀

  32. Patrick,

    Realmente te agradezco muchísimo por este artículo y por haber contestado a cada una de los comentarios que te hicieron. En el total de la página encontré el 99% respuestas que andaba buscando.

    En la empresa en la cual trabajo, hemos contratado un consultor para que nos asesore sobre los problemas de memoria y siento que no nos sirvió de nada. No nos dio respuestas seguras.
    Esta persona propuso hacer cierta cantidad de cambios y no estaba convencido de hacerlos, ya que la solución contiene 20 proyectos, y entre 5 y 20 clases por cada uno. Imaginaras lo que implicaría hacer un cambio de esa magnitud para empeorar algo que si bien no esta al 100%, se encuentra estable en producción.

    Resumiendo todo esto, GRACIAS a tu artículo, los comentarios que te realizaron y las respuestas que diste… Ya se qué cambiar!

    Te agradezco muchísimo nuevamente.

    Saludos!

  33. Hola, primero que todo quiero aradecerte por compartir este tipo de articulos en la web. Segundo quisiera compartir una experiencia que me sucedió hace poco. Yo estaba realizando una descarga de datos desde un WebService hacia una PDA,dichos WS me traía un DataSet que después recorrería para extraer sus datos. Resulta que al guardar cierto número de registros la aplicación me arrojaba una excepción de tipo OutOfMemory. Decidí utilizar el GC.Collect() y el GC.WaitForPendingFinalizers() en cada intervalo determinado de registros guardados. Eureka¡¡¡ La excepción no volvió a salir y mi aplicación aumentó un poco su velocidad!!!
    Saludos!!!!

  34. Excelente artículo que lleva dando que hablar ya 4 años, y sigue siendo de lo mejorcito del asunto. Mi más sincera enhorabuena

  35. Hola que tal. el Articulo esta bien explicado. Pero me Surge una enorme Duda, ojalá alguien me pueda ayudar.
    tego un proyecto (capa de presentacion, [negocio-Entidad] y Datos)
    1.- al ingresar a mi página(presentación) primero hago esto

    Declaro una variable de tipo Objeto.
    NombreClase obj;

    obj=null
    2.- obj= new objEntidad();

    3.- asigno valor a sus propiedades del Objeto
    obj.Nombre=”valor”;
    DS=obj.obtieneDS();

    Como Garantizo Destruir el Objeto(obj) creado Verdaderamente?.

    –Donde va el Dispose?

    en mi clase de Propiedades hago esto
    ~obj() { }

    estoy haciendo lo correcto?
    gracias por sus comentarios anticipados.
    atte.
    cdiaz

  36. Respecto al Dispose me surge una duda:

    Si tengo algo así:

    Dim f As New Form2

    If frmInputBox.ShowDialog = Windows.Forms.DialogResult.OK Then
    MsgBox(f.TextBox1.Text)
    End If

    f.Dispose()
    MsgBox(f.TextBox1.Text) ‘ESTO NO DEBERÍA DAR ERROR????!!!!!

    No entiendo porque después de la linea f.Dispose(), siguen estando accesibles las propiedades de f. ¿¿¿No era esta la principal diferencia entre Close y Dispose???

    Gracias de antemano por resolver mis dudas!!

  37. Paper,

    el objetivo de Dispose es liberar o instruir la liberación de los recursos no manejados por un objeto. En este caso específico (formulario), es posible (y probable) que el textbox no utilice recursos no manejados y por lo tanto siga funcionando. ¿qué sucede si en vez de mostrar eso, despliegas el formulario? Yo esperaría que no se pudiese desplegar.

    Finalmente, estoy de acuerdo en que una vez hecho dispose, el objeto no se debe seguir usando, aunque sharepoint lo permita e incluso reviva un objeto (barbárico).

    Patrick

  38. Efectivamente, después de Close() o Dispose() no se puede volver a desplegar el formulario.

    Como conclusión, ¿podriamos decir que, para un formulario que NO utilza recursos no manejados (conexiones a BD, sockets, ficheros,…) es indistinto el uso de Dispose() o Close() a efectos de rendimiento de memoria?

    Grácias de nuevo por tus comentarios Patrick!

  39. ””Ahí es donde se puede hacer la diferencia. Si yo sé que no se usarán más adelante en la función, entonces puedo igualarlos a nulo y en la eventualidad que se produzca una recolección, estos serán efectivamente recolectados por el GC (no envejecerán) y la memoria será liberada.””

    Efectivamente. Doy fe de ello.
    MI aplicación se descarga Datasets de un servidor central que sirven para grabar unos ficheros xml dísicamente en el disco duro local de la aplicación cliente.

    En cuanto tengo esos archivos XML guardados en disco, igualo los Datasets a nothing (son Datasets que pesan mucho) y fuerzo manualmente el GC.Collect

    Observando la gestión de memoria del Administrador de Tareas puedo comprobar como la totalidad del peso de los Datasets desaparece de mi monto de memoria utilizada

    Pero te haré caso y untiilzaré Dispose ya que ahora tengo qeu atajar otro problema en la capa de Dominio de mi aplicación con el consumo de memoria de clases creadas que dejan de estar referenciadas.

    Muchísimas gracias por el artículo
    MUY INTERESANTE

  40. Antes de llegar a esta página encontré un snippet para liberar memoria, por una dll creada por mí, que se nota que dejaba basura. Bueno, le metí un timer cada 5 minutos llamando a esta función y funciona genial. Por lo menos, eso es lo que dice el administrador de tareas, no sé si habrá que buscar el síntoma negativo en algún otro lado.

    Por las dudas, les dejo el código que usé yo: http://www.dreamincode.net/code/snippet3257.htm

    ¡Saludos!

  41. you love this? [URL=http://tampa-bay-buccaneers.net/dallas-clark-limited-black-game-jerseywhite-elite-men-jerseyred-youth-women-jersey/ – dallas clark youth jersey[/URL – to your friends CWEJcMOG [URL=http://tampa-bay-buccaneers.net/dallas-clark-limited-black-game-jerseywhite-elite-men-jerseyred-youth-women-jersey/ – http://tampa-bay-buccaneers.net/ [/URL –

  42. I had been very happy to discover this web-site.I needed to thank you for some time because of this amazing read!! I undoubtedly enjoying every single small little it and I have you bookmarked to take a look at new stuff you blog post.

    Am I Able To just say what a relief to locate someone who truly knows what theyre talking about on the internet.

    jordan 13

  43. You will discover some interesting points in time in this post but I don’t know if I see all of them center to heart. There’s some validity but I will take hold opinion until I appear into it further. Wonderful write-up , thanks and we want even more! Added to FeedBurner at the same time

    NFL Authentic Jerseys
    Personalized NFL Jerseys

  44. You produced some decent points there. I looked online for the concern and discovered most people will go along with with your website.
    An impressive share, I just given this onto a colleague who was performing just a little analysis on this. And he the reality is bought me breakfast because I found it for him.. smile. So let me reword that: Thnx for the treat! But yeah Thnkx for spending the time to talk about this, I really feel strongly about it and really like reading more on this subject. If probable, as you develop into expertise, would you mind updating your blog with even more details? It really is extremely helpful for me. Huge thumb up for this weblog post!

    Mitchell and Ness Jerseys

    http://jerseys205.0fees.net/

  45. You created some decent points there. I looked on the net for the concern and located most people will go along with together with your site.

    Cheap NFL Jerseys

    cheap louis vuitton bags

  46. When I originally commented I clicked the -Notify me when new comments are added- checkbox and now each and every time a comment is added I get four emails using the identical comment. Is there any way you are able to get rid of me from that service? Thanks!

    NFL Authentic Jerseys
    NFL Authentic Jerseys

  47. Immediately after study several of the weblog posts on your website now, and I truly like your way of blogging. I bookmarked it to my bookmark web site list and are going to be checking back soon. Pls take a look at my internet web site at the same time and let me know what you believe.

    Wholesale NFL Jerseys
    Wholesale NFL Jerseys

  48. Youre so cool! I dont suppose Ive read something like this just before. So nice to discover somebody with some original thoughts on this topic. realy thank you for starting this up. this web page is some thing which is required on the internet, a person having a small originality. useful job for bringing some thing new to the net!

    womens jordans free shipping

    womens Nike free sko

  49. you have an incredible blog here! would you like to make some invite posts on my weblog?
    I’m commonly to blogging and i genuinely appreciate your content. The article has really peaks my interest. I’m going to bookmark your web page and maintain checking for new details.

    Personalized NFL Jerseys

    http://jerseys205.0fees.net/

  50. Immediately after study a number of of the blog posts on your website now, and I really like your way of blogging. I bookmarked it to my bookmark internet site list and will likely be checking back soon. Pls have a look at my web web site too and let me know what you feel.

    Cheap NFL Jerseys

  51. This is the right weblog for anyone who desires to discover about this subject. You realize so much its virtually challenging to argue with you (not that I actually would want?-HaHa). You certainly put a new spin on a subject thats been written about for years. Wonderful stuff, just great!

    michael kors bags on sale

  52. Excelente artículo, pero tengo un problema similar al tratado, en visual basic en VS 2012, habro excel en un boton que genera un archivo de esta forma.

    Dim MiExcel As New Excel.Application
    Dim MiLibro As Excel._Workbook
    Dim MiHoja As Excel._Worksheet
    MiHoja = CType(MiLibro.Sheets(1), Excel._Worksheet)

    Lleno el archivo y lo cierro y guardo asi.

    MiLibro.SaveAs(sArchivo)
    MiExcel.Quit()
    MiExcel = Nothing

    Pero al abrir el administrador de tareas, esta excel abierto tantas veces como archivos creados.
    ¡Como puedo cerrar excel desde la aplicación antes de cerrarla,? ya que aun permanece despues de cerrado el programa.

  53. Youre so cool! I dont suppose Ive read anything like this ahead of. So nice to uncover somebody with some original thoughts on this subject. realy thank you for starting this up. this web-site is something which is needed on the web, a person having a small originality. valuable job for bringing some thing new to the web!

    Youth NFL Jerseys

    http://jerseys205.a0001.net/

  54. You will discover definitely plenty of details like that to take into consideration. That’s an excellent point to bring up. I present the thoughts above as general inspiration but clearly you can find questions like the 1 you bring up where essentially the most imperative thing is going to be working in honest good faith. I don?t know if most beneficial practices have emerged about points like that, but I am positive that your job is clearly identified as a fair game. Both boys and girls really feel the impact of just a moment’s pleasure, for the rest of their lives.

    uggs cheap

  55. I’m impressed, I have to say. Truly rarely do I encounter a weblog that’s both educative and entertaining, and let me tell you, you’ve hit the nail on the head. Your idea is outstanding; the concern is something that not enough consumers are speaking intelligently about. I’m particularly pleased that I stumbled across this in my search for some thing relating to this.

    Personalized NFL Jerseys
    NFL Jerseys

  56. Can I just say what a relief to discover an individual who actually knows what theyre talking about on the web. You undoubtedly know how to bring an issue to light and make it very important. Alot more many people need to read this and understand this side of the story. I cant think youre not extra common for the reason that you surely have the gift.

    michael kors macy s
    michael kors online

  57. Following study some of the weblog posts on your web page now, and I genuinely like your way of blogging. I bookmarked it to my bookmark web site list and might be checking back soon. Pls take a look at my internet web site too and let me know what you believe.

    mk bags

  58. Aw, this was a genuinely nice post. In thought I would like to put in writing like this in addition – taking time and actual effort to make a especially excellent article?- but what can I say?- I procrastinate alot and by no indicates appear to obtain something done.

    air jordans shoes

  59. ESPN鈥檚 Adam Schefter reports it will be a 鈥渕ajor upset鈥?if free agent FB Vonta Leach doesn鈥檛 sign with the Dolphins. This is not a huge surprise since the Dolphins are throwing major change at people this offseason.聽 鈥淸The] Dolphins want him too much,鈥?added Schefter. Miami has been the most logical fit for the 31-year-old, but money is going to be the deciding factor. If we鈥檝e learned anything this offseason, it鈥檚 that GM Jeff Ireland will shell out cash for any player he feels he needs. Talks were reportedly 鈥渉eating up鈥?last Friday, but cooled over the weekend as the Giants jumped in. Leach said Monday that he鈥檚 in 鈥渘o rush鈥?to sign, so this could drag out for a few days, but don鈥檛 expect it to go a different direction, unless the Ravens make a great offer.聽 My question is what will the Dolphins do with Javorski Lane, that kid is a freak.聽 We shall see, but Schefter usually calls good money.
    Eric Staal jersey http://www.bindaaspoll.com/jobs/Johnsonjerseys.aspx?4

  60. NOTES: Braves RHP Julio Teheran (13-8, 3.09 ERA) will start Sunday against 31-year-old journeyman Zach Miner (0-1, 3.08), who began his professional career in the Braves’ organization. … Braves manager Fredi Gonzalez said C Brian McCann’s strained adductor is improving, and he may get an at-bat or two Sunday. McCann has not played since leaving Thursday’s game after two innings with a strained right groin.

    Terry Glenn jersey http://au.fulltimejobs.com/images/Geraldjerseys.aspx?2

  61. 3rd r quite a long time, and its particular company lifestyle may usually lasts intended for above 10 years, with all the totes condition & pattern remaining not really out-of-date. Liberación de memoria en código manejado (¿Dispose, Finalize, Object = Nothing, GC.Collect?) – la visión de un ingeniero de campo Resulting from 人気スニーカー メンズ http://www.pravoslavieto.com/newblances.html that, many normal young women are generally using to acquire one particular Gucci hand bags, that could be their own li.

Leave a Reply

Your email address will not be published. Required fields are marked *