30 noviembre 2005

Liberar Memoria Con Vb .NET

Posted in VB.NET Develop a 4:16 pm por jabelSan

Chequeando una aplicación que estoy desarrollando, he verificado el uso excesivo de memoria que consumen las aplicaciones desarrolladas en NET FrameWork.

Despues de probar que descargaba correctamente todos los objetos que utiliza la aplicación mediante el uso del Dispose() y especificamentes los objetos DataSet y DataTable, ya que estos hay que descargarlos de memoria manualmente, observe que la memoria seguia sin descargarse correctamente. Por lo que probe con el GC (Garbage Collector) para forzar la liberación de memoria, pero el resultado fue identico.

Despues de probar, recompilar, optimizar el código fuente opte por «obligar» a la aplicación (al proceso) por completo a liberar la memoria no necesaria. Para ello me enfunde en el manejo de las Api’s, localizando SetProcessWorkingSetSize, que fuerza al proceso dado a liberar la memoria no usada (como cuando minimizas la aplicacion). Para ello me desarrolle la funcion ClearMemory, accesible desde cualquier punto de la aplicación que me permite optimizar el uso de memoria por parte del NET FrameWork.

‘Declaración de la API
Private Declare Auto Function SetProcessWorkingSetSize Lib «kernel32.dll» (ByVal procHandle As IntPtr, ByVal min As Int32, ByVal max As Int32) As Boolean

‘Funcion de liberacion de memoria
Public Sub ClearMemory()

    Try

      Dim Mem As Process
      Mem = Process.GetCurrentProcess() SetProcessWorkingSetSize(Mem.Handle, -1, -1)

    Catch ex As Exception
    ‘Control de errores
    End Try

End Sub

66 comentarios »

  1. eduardo said,

    hola maigo me parec eun execelente ejercicio, pero me gustaria saber si me puede explicar con mazanitas el SetProcessWorkingSetSize ya que lo que he encontrado en la web no me ayuda y que funcion tiene con el GC muchas gracias de ante mano

  2. Delo said,

    Acojonante …

  3. jose said,

    MUY BUEN POST muchas gracias el unico problema es ke no los Gurus de .net no lo recomiendan ..
    pero excelente..

  4. cajina said,

    Me podrias explicar como usarlo y cuando?.
    Es que estoy tratando de liberar punteros de una lista, recorriendo la lista hasta el final usando un procedimiento recursivo y tratando de liberar la memoria desde el ultimo hasta el primer puntero.
    Pero no he podido asi que hasta el momento lo que he hecho es asignar Nothing a cada uno de lo punteros y limpiarlos.

  5. cajina said,

    Y no se exactamente como trabaja ese procedimiento…
    Jijijijiji
    Gracias…

  6. Alfonso May said,

    Excelente…

  7. tina said,

    Una función fantàstica.
    Empezaba a volverme loca intentando reducir la memoria de mi programa, poniendo el colector en todos sitios sin conseguir nada, hasta que encontrado tu funcion.
    Gracias por compartir tan esplendida función.

  8. Jorge said,

    Con SetProcessWorkingSetSize lo q haces es descargar toda la memoria al archivo de intercambio, luego a partir de ahí se supone q windows solo recupere la parte q necesita. Esto lo puedes ver facilmente con el task manager si escoges ver la columna VM Size para tu proceso.

    Si alguien tiene un arreglo de punteros de codigo no administrado antes yo trataria de recorrer el arreglo, desbloquear la memoria de cada uno y liberarla de la misma manera q quizas la reservo con GlobalLock. O sea, usando APIs q con VB como el ejemplo seria algo así:

    If _mypptr IntPtr.Zero Then
    GlobalUnlock(_mypptr )
    GlobalFree(_mypptr )
    End If

    _
    Friend Function GlobalLock(ByVal handle As IntPtr) As IntPtr
    End Function

    _
    Friend Function GlobalUnlock(ByVal handle As IntPtr) As Boolean
    End Function

    _
    Friend Function GlobalFree(ByVal handle As IntPtr) As IntPtr
    End Function

    _
    Friend Function GlobalAlloc(ByVal flags As Integer, ByVal size As Integer) As IntPtr
    End Function

    _
    Private Function SetProcessWorkingSetSize(ByVal process As IntPtr, _
    ByVal minimumWorkingSetSize As Integer, _
    ByVal maximumWorkingSetSize As Integer) As Integer
    End Function

  9. Jorge said,

    Otra cosa q olvide es con credenciales de adm no tendras problemas pero si el usr q ejecuta tu app no tiene el privilegio adecuado (PROCESS_SET_QUOTA) (La seguridad de Windows incluye la gestión privilegios sobre procesos)
    no podras invocar la funcion SetProcessWorkingSetSize y es posible q ocurran algunas cositas en dependencia del servipack, version, configuracion, etc del equipo como q se audite en el Identificador de sucesos de windows, cierre de la app, etc. EJEMPLO EN http://support.microsoft.com/kb/831905/en-us

    Tambien esto solo funciona sobre WIn32 asi q es valido verificar la plataforma:

    If (Environment.OSVersion.Platform = PlatformID.Win32NT) Then
    Dim Mem As Process = Process.GetCurrentProcess()
    SetProcessWorkingSetSize(Mem.Handle, -1, -1)
    End If

  10. Perriko said,

    Va tan fino, que uno no se lo puede creer.

    Tengo que matizar algo sobre lo que he leido.

    VB si que libera la memoria cuando llamais a dispose y a GC, se marca como libre, pero se deja asignada al proceso, para reutilizarla en posteriores solicitudes (y como ya sabeis suelen ser muy posteriores), con esta llamada se obliga a reducir el tamaño de la memoria global asignada a la que realmente está utilizando el proceso:
    En mi caso: he pasado de 110 megas a 8 Megas, lo gracioso es que ahora el monitor de memoria parece una montaña rusa.

  11. fishertrout said,

    Impresionante!!!! Los problemas que tengo de memoria al trabajar todos los usuarios en Terminal Server!!!!!!!! Ahora me falta provar que funcione.

    La aplicación me comía mucha memoia del servidor.

    90 Mb x 20 usuarios = 1,8Gb !!!!!!!!!!!!!!!!!!!!!!!

    Si todo va bien…..

    15 Mb x 20 usuarios = 0,3Gb

    Mejoria, no……..

    Buen trabajo.

  12. fishertrout said,

    Para quien lo necesite, también funciona en terminal server. Lo digo por tema de permisos y esas cosas.

    fuuuuaaaaaaaaaaaaaa!!!!!

  13. eric arturo said,

    Excelente aplicacion,habia creado controles dinamicos ,toda iba bien
    lo unico era la enorme cantidad de recursos que consumia ahora cuando ejecuto todo solo me pasa de 3 a 2 genial FUNCION
    GRACIASSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS

  14. LINCHIS said,

    Muchas gracias! me ha venido de lujo! 😉

  15. Marco Esparza said,

    Mis felicitaciones es una exelente funcion, la neta morro que pesado estas .
    GRACIAS Y MUCHO EXITO.

  16. Marcos Garcia said,

    Muchas gracias por publicar esta post , la verdad que fue de mucha ayuda pero una pregunta adicional , para que esto corra tambien desde una aplicacion web que deberia considerar?

  17. Carlos Aristegui said,

    O.O! increible! de 200.000 KB que consumia mi aplicación baja a 2.000 KB! es la hostia esto, ya no me tengo q preocupar del mal uso que hago de la memoria XD. Muchas gracias por el aporte!

  18. Quique said,

    EXCELENTE LOCO!!! Le salvaste la vida a varias personas!

  19. Giovanni Cedeño Prendas said,

    Muchas gracias viejo me salvastes. Muy buen trabajo

  20. Luis Roberto Serrano said,

    excelente rutina…muy buena solucion

  21. Raul said,

    Excelente….

    Un servicio de nada que espera ficheros y envía mail, me ocupaba 12 Mb y ahora pasa a 1.

  22. Carlos said,

    EXCELENTE MUCHAS GRACIAS FUNCIONA DE MARAVILLA,

    DESPUES CARGAR UN TREMENDA TABLA DE 500000 FILAS ME QUEDABA EN MEMORIA UNA CARGA DE 600MB AHHORA LIBERANDO TABLA QUEDA EN 20 MB JJJAJAJAJJ EXCELENTE

  23. SysEdw said,

    Felicitaciones, Q funciona como un programador desea que su sistema no pesara tanto que es el peor terror de todos nosotros.

  24. Pedro Antonio Peláez said,

    Para liberar memoria en Net de forma explicita se puede usar nulo, si asignas nulo a una array o a cualquier variable, que no necesite «dispose», el recolector la dara de baja inmediatamente de la memoria. Esto viene muy bien en algoritmos recursivos, que tienden a mantener memoria inutil acumulada.

    La unica pega es que tienes que revisar el codigo a optimizar y asignar nulo a cada variable que ya no uses.

    Un saludo 🙂

  25. Luis said,

    Hola,

    Perdón mi ignorancia, pero alguien puede indicarme como hacer uso del método en una aplicación?

    Saludos.

  26. cristian said,

    maravilloso…. redujo en mas de la mitad el uso de memoria de mi app..
    notable…

  27. kX said,

    De 28mb baja a 5 cada vez que cierro una ventanita de configuraciones 😀
    Muchas Gracias.

  28. kX said,

    wooow no habia visto, el post es del 2005! y nos sigue funcionando a muchos.
    Eres poderoso Mercenario 😀

    • Mercenario said,

      Y tres años después de tu comentario por lo visto le sigue funcionando a mucha gente, sigo estando impresionado el resultado de las «cuatro» lineas de código que decidí compartir, aunque no sean las mejores que haya hecho, la satisfacción que me ha dado por hacerlo lo recompensa.

  29. el tito jari said,

    Muy buena la función. casi un 70% menos de memoria.

    Enhorabuena.

    Gracias!

  30. Carlos Rosario said,

    Excelente solución, simple pero efectiva.

  31. Amador said,

    Esto, chicos, una pregunta.

    Donde y cuando colocais la llamada a la función, despues de cada procedimiento o función ‘pesados’?

  32. Mercenario said,

    Lo más correcto, desde mi punto de vista, es usarla cuando sometamos la aplicación/proceso/actuación a un segundo plano.

    Estar descacheando/liberando/desechando memoria usada a cada paso de trabajo de carga no lo veo lógico, tambien depende de los procesos o funciones de carga «pesados» usados.

    La memoria usada «de vez en cuando es cacheada» intencionalmente, respetad su consumo.

  33. julio said,

    muchisimas gracias funka ed maravilla!!!

  34. Strong said,

    y cuando debo de llamar a la funcion??
    por ejemplo si estoy usando dataset? lo puedo llamar cuando cierre el formulario??

    otra cosa si estoy trabajando en 64bit funciona??

    gracias.

  35. viper said,

    Felicidades…. no manches funciona de maravilla.

    saludos.

  36. miguelcr1982 said,

    Mae sos un monstruo, demasiado buena!!!, gracias!!!!

  37. Ricardo said,

    (BRASIL) Muito bom! Injeção na veia!

  38. gochy said,

    Wooooooow!!!…
    Muchas felicidades y graciaaaaas!!!…
    Buscaba una solución así de buena como la tuya….

    desde Costa Rica: Pura vidaaaaaaa!!!!

  39. Freddy Espinoza said,

    la rutina libera memoria en forma correcta, sin embargo aún tengo el maldito error de Exception of type ‘System.OutOfMemoryException’ was thrown. al tratar de grabar en memoria un archivo PDF que estoy utilizando con la DLL de ASPPDF, ésta se cae en forma aleatoria al llegar a un límite que aún no tengo claro cual es.

  40. Pedro said,

    Muy buena la rutina pero he observado que gracias a ella la columna (en el monitor de recursos de windows 7) espadcio de trabajo desciende fantasticamente, aunque la columna Asignación no baja tanto (columna que dice literalmente «cantidad de memoria reservada por el so para el proceso»). En mi caso tengo un vlc que reproduce fotos de un álbum y gracias a la función he conseguido que la columan espacio de trabajo baje. Sabe como bajar la columna de Asignación? Gracias

    • Matute said,

      me pasa lo mismo que a vos, tengo mi aplicacion que con el código baja la memoria de trabajo pero no la asignada, pudiste solucionar ese problema???

  41. Jaime Alex said,

    Exelente Post…..

  42. sergio aguirrezabala said,

    Excelente (claro, sin ennrosques, 200% funcional) muy muy bien

  43. Sercho said,

    Muchas gracias, mi programa empezaba a subir muy rapido 10, 50, 100, 200, 400, 500 MB y asi en menos de un minuto!!! solo trabajaba con objetos Graphic pero los liberaba con dispose() y no servia 😛 ahora no pasa de los 3 MB 🙂

    Excelente Gracias de nuevo! saludos!

  44. Negron said,

    Este codigo funciona en cualquier plataforma? Bien sea x86 o x64.

  45. Sergio said,

    Muy, muy bueno. Me ha sacado de un buen apuro. Muchas gracias.

  46. Federico said,

    Gracias loco por tu aporte, muy bueno, mi aplicacion estaba volviendome loco, estaba por el mismo camino que vos, pero llegaste antes.

    FEDE

  47. Carlos said,

    Muy buenas, gracias por el aporte solo que a mi no me funciona aun, estoy dando vueltas pero no logro ver el resultado esperado, uso vs team system 2008 (VB.net) y aparece un error

    ‘THE TARGETED VERSION OF COMPACT FRAMEWORK DOES NOT SUPPORT USING AUTO ‘

    y en SetProcessWorkingSetSize(Mem.Handle, -1, -1) , Mem.handle no es miembro de system.diagnostic.process

    help me please !!!

  48. Carlos said,

    de paso te comento mi hermano que yo lo que quiero es liberar memoria con una aplicacion para smartdevice… al querer llamar a otro formulario form2 desde un principal form1, lo logro ver claro, y desde el form2 regresar al form1 pero se van cargando en cada llamada los formularios en memoria de manera que me genera conflictos con datos mostrados anteriormente. Uso dispose() para liberar memoria pero el problema persiste.

    He combinado varias formas una de ellas:

    Dim objForm As New frmListaProductos
    Try
    objForm.ShowDialog()
    frmListaProductos.ShowDialog()
    Finally
    Me.Close()
    Me.Dispose()
    System.GC.Collect()

    otro es:

    frmListaProductos.ShowDialog()
    Me.Close()
    Me.Dispose()
    System.GC.Collect()

    pero no doy !

  49. luis said,

    no compila, me dice
    el tipo process no esta definido 😦

  50. Excelente, estaba utilizando hilos y demas cosas que hacian que mi aplicación no se cerrará. Con este programita se cierra sin problemas
    Thanks

  51. Albi said,

    dos palabras Imp Presionante….

  52. Jorge B. said,

    ESPECTACULAR. Me resolviste un problema terrible. Muchísimas gracias. Un GENIO.

  53. katty said,

    Increíble, gracias x compartirlo.

  54. Sandro said,

    Obrigado, Gracias ótimo código!

  55. Paul Ventura said,

    SetProcessWorkingSetSize(Mem.Handle, -1, -1) me da error dice se esperaba que fin de la instruccion???

    • Luis Basurto said,

      Me imagino que solo copiaste y pegaste el codigo, el error es porque no se pega exactamente igual, debes poner esa instrucción en una sola linea separada de las demás instrucciones…

      Revisa que te quede exactamente igual como esta publicado.

  56. Edu said,

    Si es verdad que reduce la memoria como indicais muchos, pero que pasa con la memoria virtual? Cuanto más reduce la memoria más aumenta al virtual…lo podeis ver en el administrador de tareas.
    ¿Alguien sabe si hay forma de reducir la memoria virtual de una forma parecida?

    • Mercenario said,

      Te recomiendo echar un ojo a los comentarios, algunos son interesantes sobre el tema.
      Hace tiempo estuve mirando el tema de reducir la memoria de cacheo y si, se puede, pero no es nada recomendable. Si ya partimos de que esta forma de liberación no es «correcta» en si, el fuerce a liberación de memoria de cacheo lo es menos, pues es más interno.

      Personalmente en el tema de memoria de cacheo prefiero dejar al SO administrarla, una cosa es liberación de memoria y otra forzarlo.

  57. Hola! Tengo una sistema contable, al que le estoy añadiendo la parte comercial… Utilizo varios dataSets, dataTable, BindingSource, no puedo generarla por que me sale system.OutOfMemoryException…

  58. Anthony said,

    Buenas, soy analista programador.
    Un tiempo desarrolle una aplicacion con VS 2010 y sql server 2008 R2
    las clases estaban contenidas dentro de la Aplicacion(no en una biblioteca de clases), pero esta consume menos memoria mientras esta sin uso
    Actualmente estoy desarrollando otra aplicacion con VS 2012 y Sqlserver2008 R2 (las clases estan contenidas en una biblioteca de clases, pero esta esta consumiendo mas memoria mientras se esta sin uso, por su puesto esta aplicacion es mas grande que la primera

    La pregunta es depende el tamaño de la aplicacion el consume de memoria, porq la verdad me intriga este detalle…
    Saludos…!

  59. Luis Basurto said,

    Respuesta a: Paul Ventura said

    21 octubre 2012 a 5:26 am

    SetProcessWorkingSetSize(Mem.Handle, -1, -1) me da error dice se esperaba que fin de la instruccion???

    Me imagino que solo copiaste y pegaste el codigo, el error es porque no se pega exactamente igual, debes poner esa instrucción en una sola linea separada de las demás instrucciones…

    Revisa que te quede exactamente igual como esta publicado.

  60. Carlos Otero said,

    Gracias por compartir este procedimiento, en la vida lo hubiera descubierto yo, programo en WPF, y es la única forma de liberar los formularios al cerrarlos, incluyendo esta función el el evento Closing. Gracias, de corazón.

  61. Rod said,

    Hola, eso está muy bien para WIN32, pero en 64 bits como seria?
    Gracias

  62. prueba4771 said,

    Excelente aporte 🙂


Replica a Perriko Cancelar la respuesta