30 noviembre 2005

Liberar Memoria Con Vb .NET

Publicado en VB.NET Develop a 4:16 pm por Mercenario

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

About these ads

61 comentarios »

  1. eduardo escribió,

    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 escribió,

    Acojonante …

  3. jose escribió,

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

  4. cajina escribió,

    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 escribió,

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

  6. Alfonso May escribió,

    Excelente…

  7. tina escribió,

    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 escribió,

    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 escribió,

    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 escribió,

    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 escribió,

    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 escribió,

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

    fuuuuaaaaaaaaaaaaaa!!!!!

  13. eric arturo escribió,

    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 escribió,

    Muchas gracias! me ha venido de lujo! ;)

  15. Marco Esparza escribió,

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

  16. Marcos Garcia escribió,

    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 escribió,

    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 escribió,

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

  19. Giovanni Cedeño Prendas escribió,

    Muchas gracias viejo me salvastes. Muy buen trabajo

  20. Luis Roberto Serrano escribió,

    excelente rutina…muy buena solucion

  21. Raul escribió,

    Excelente….

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

  22. Carlos escribió,

    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 escribió,

    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 escribió,

    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 escribió,

    Hola,

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

    Saludos.

  26. cristian escribió,

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

  27. kX escribió,

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

  28. kX escribió,

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

    • Mercenario escribió,

      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 escribió,

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

    Enhorabuena.

    Gracias!

  30. Carlos Rosario escribió,

    Excelente solución, simple pero efectiva.

  31. Amador escribió,

    Esto, chicos, una pregunta.

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

  32. Mercenario escribió,

    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 escribió,

    muchisimas gracias funka ed maravilla!!!

  34. Strong escribió,

    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 escribió,

    Felicidades…. no manches funciona de maravilla.

    saludos.

  36. miguelcr1982 escribió,

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

  37. Ricardo escribió,

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

  38. gochy escribió,

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

    desde Costa Rica: Pura vidaaaaaaa!!!!

  39. Freddy Espinoza escribió,

    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 escribió,

    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 escribió,

      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 escribió,

    Exelente Post…..

  42. sergio aguirrezabala escribió,

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

  43. Sercho escribió,

    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 :P ahora no pasa de los 3 MB :)

    Excelente Gracias de nuevo! saludos!

  44. Negron escribió,

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

  45. Sergio escribió,

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

  46. Federico escribió,

    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 escribió,

    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 escribió,

    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 escribió,

    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 escribió,

    dos palabras Imp Presionante….

  52. Jorge B. escribió,

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

  53. katty escribió,

    Increíble, gracias x compartirlo.

  54. Sandro escribió,

    Obrigado, Gracias ótimo código!

  55. Paul Ventura escribió,

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

  56. Edu escribió,

    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 escribió,

      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 escribió,

    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…!


Deja un comentario

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

Seguir

Recibe cada nueva publicación en tu buzón de correo electrónico.

%d personas les gusta esto: