Jul 14

Ajax, navegadores y la memoria

Antes de nada debe quedar claro que no he hecho pruebas en serio, lo que comento a continuación es simplemente lo que me he encontrado sin ir más allá.

Como he comentado en post anteriores, estamos (estábamos, ya se ha entregado) haciendo un portal web en el que hay varias cosas implicadas. El portal es de página única, es decir, entras en sesión y te muestra un mapa (geoserver/openlayers), unas tablas de datos y un chat. No cambias de página en ningún momento y todas las actualizaciones se hacen de forma automática y cada cierto tiempo con ajax.

Nuestro mapa se actualiza usando la librería openlayers. El chat está hecho con GWT, por lo que no hacemos nada de javascript a mano. Las tablas con una extensión de jQuery y se actualizan solitas con ajax. Todo funciona bien, pero hay las siguientes pegas con la memoria.

Por un lado, con internet explorer, si lo dejamos abierto y no tocamos nada, las actualizaciones se hacen solitas cada cierto tiempo y mirando el administrador de tareas de windows vemos que la memoria consumida por Internet Explorer no sube. Tras 24 horas abierto sin salvapantallas de ningún tipo, todo sigue correctamente. Pero ….. si trabajamos con la web (hacemos zoom en el mapa, creamos datos, borramos datos, chateamos, etc, etc, etc), la memoria consumida por internet explorer va creciendo a pasos agigantados. El navegador empieza a ir lento, luego deja de responder y en ocasiones, al final, incluso ha dejado de responder el PC y ha habido que apagarlo de malas maneras.

Por otro lado, con Chrome el comportamiento es bien distinto. Si lo dejamos 24 horas mostrando el portal sin tocar nada, la memoria va creciendo poco a poco. Desde unos 100 Megas en el arranque hasta 1 Giga o Giga y medio tras 24 horas. Pero a pesar de la memoria consumida, Chrome y la aplicación web siguen funcionando igual de ágiles que al empezar. Y si abres la web con Chrome y trabajas en ella, la memoria va crenciendo poco a poco, pero se va también liberando y el resultado final es que crece incluso de forma más lenta que si no tocas nada. Me da la impresión de que Chrome libera memoria según cambias de pestaña, lo minimizas, lo pones detrás de otras ventanas, etc, etc. Y en ningún caso, como en Internet Explorer, nos ha dejado de funcionar ni mucho menos nos ha colgado el PC.

Probando con otras web de las que hay por internet que tengan actualizaciones automáticas cada cierto tiempo (por ejemplo, la misma página de inicio de iGoogle con tus feeds mostrados), veo que también van consumiendo memoria del navegador poco a poco. No he probado a tenerla 24 horas abierta, así que no sé si se estabiliza o no.

Y buscando por internet cosas sobre "memory leaks" en javascript, gwt, openlayers, explorer, chrome … el resultado es desesperanzador. Por lo visto son problemas muy, muy habituales, que requieren una programación muy muy cuidadosa, en la que hay que saber miles de truquillos para hacerlo bien … y como siempre en estos casos, hay trucos específicos para cada navegador o incluso navegadores (internet explorer) que requieren una atención especial.

En fin, me temo que javascript/ajax/navegadores web no están pensados/preparados para aplicaciones web que deben mantenerse abiertas de forma permanente. Están más pensadas para abrir el navegador, ver la página, jugar un rato con ella (un minuto, una hora, dos horas,….) y pasar a otra cosa.

Y en el caso concreto de GWT me ha llamado la atención un comentario que encontré en un foro. Alguien con GWT tenía problemas de pérdida de memoria y buscando por internet encontró lo mismo que yo: "GWT está muy bien pensando y no tiene problemas de memoria", así que su comentario en el foro era el que podía haber escrito yo mismo: "Tengo una aplicación con GWT y problemas de memoria. Buscando en google la solución que encuentro es que GWT es maravilloso y no tiene problemas de memoria. Así que sigo teniendo problemas de memoria"

Entradas relacionadas:

3 Responses to “Ajax, navegadores y la memoria”

  1. Josep Sanz Says:

    Buenas tardes.

    Es totalmente cierto lo que comentas.

    Yo, con la aplicación SaltOS, lo que tuve que hacer para controlar el crecimiento de memoria y CPU descontrolado fue programar un sistema de garbage collector (es muy sencillo y quizás por ello funciona bien).

    Un error típico es reemplazar contenido usando ajax, pero que pasa con lo que había antes??? si cargas una página con ajax y programas binds a ciertos elementos de la nueva página, cuando luego lo reemplazas sin deshacer los binds (con unbind por ejemplo), el navegador no es capaz de liberar la memoria y CPU empleada en los binds. Ten en cuenta que al final de todo, hacer un bind del evento hover en un botón no es otra cosa que decirle al scheduler del navegador que cuando pases por ese botón, ejecute una función que tu le has dicho y eso se traduce en que cada x tiempo, el navegador mirara la posición del cursor y si estas encima del boton, entonces ejecutará la función. Si esto no se limpia, además de la memoria, estamos usando CPU que consumirá recursos y hará que cada vez se ejecute más lentamente la aplicación.

    La solución que yo implementé con SaltOS fue crear un reemplazo del $.html(), (como verás, yo uso JQuery) que permite en lugar de reemplazar directamente, mover el contenido a otra zona del DOM que tengo para ese propósito y poner el nuevo contenido. Cuando acabo todas las operaciones de actualización, lanzo una función de recolección del garbage collector que lo que hace es ir borrando de forma controlada todos los elementos de la zona #gc.

    En el momento de cargar el nuevo contenido, mi objetivo es mostrar rápidamente la nueva pantalla, con lo que no quiero perder tiempo haciendo la recolección. Quiero que el cliente tenga la sensación que la carga a finalizado y mientras el mira el resultado de la carga, yo en background (con un setTimeout, por ejemplo), lanzo una rutina que hace la recolección, todo esto sin bloquear el interfaz y sin que el usuario sufra las consecuencias de tener que esperar.

    De hecho, SaltOS esta lleno de estos trucos que permiten dar una sensación agradable al usuario (de todas maneras, cada día aprendo más cosas y mejoro lo existente).

    No se si te he ayudado mucho con esta explicación.

    Josep.

  2. Chuidiang Says:

    Sí, me ha ayudado, gracias. Había visto por ahí lo de los bind y el reemplazar html. La gente propone soluciones parecidas a la tuya, o poner a null todos esos bind antes de reemplazar html y cosas similares. No me he metido en serio con ello, en parte por falta de tiempo y en parte, como digo en el post, porque casi todo el código javascript es de terceros (openlayers, jquery, gwt) y nosotros no hacemos más que “pegar” los trozos. No quiero decir que estas herramientas/librerías tengan pérdidas de memoria, quizás nosotros no las usamos adecuadamente. Tengo pendiente darle un repaso a todo esto, tenemos en vista más proyectos con portal web (e incluso una ampliación del ya entregado) y conviene aprender de los errores.

    Se bueno.

  3. Antonio Manuel Muñiz Says:

    Hola,

    ¿Has probado ExtJS? Yo lo uso día a día (en varios proyectos) y por ahora nos va muy bien, ningún usuario se ha quejado. Eso sí, hay que programar en javascript, pero si se usa bien el framework es una gozada.

    Un saludo.

Leave a Reply