24 marzo 2006
El tamaño no importa
Esta semana nos ha tocado ir de conferencias: el martes en los Tech Days de Sun y ayer en la presentación de un nuevo producto para la gestión de la configuración.
El caso es que, mientras los distintos ponentes contaban sus historias, presentaban sus productos y demás, yo me iba dando cuenta de lo difícil y distinto que es programar juegos para móviles. Que si bases de datos relacionales, que si frameworks de mapeado R/O, arquitecturas basadas en servicios web, AJAX, OpenGL... y mientras tanto nosotros pegándonos con los desplazamientos de bits, o haciendo malabarismos para evitar esos dichosos arrays de 3 dimensiones que hacen que el heap explote.
Y es que, como bien decía Joel, aunque todos los programadores nos dediquemos a programar, los mundos en los que nos movemos son radicalmente distintos.
Os voy a contar un caso nuestro, que ya ha comentado Jaime por encima: nuestros juegos son bastante grandes, sobre todo teniendo en cuenta las capacidades de algunos móviles que soportamos. Por poneros en situación, El Cuarto Sello tiene 12 niveles y 9 tipos distintos de enemigos. Esto lo pone al nivel de muchos juegos de PC, pero metido en un móvil con 500 KB de memoria. Esto nos obliga a exprimir al máximo la memoria del teléfono, y como decía Jaime, hay muchas cosas que están
en el heap cuando no estaba previsto que estuvieran.
Si te dedicas a programar aplicaciones de escritorio o servidor, seguramente no te habrás parado a pensar si estás desperdiciando espacio en la memoria. Te bastará con que no haya memory leaks y que el consumo de memoria no se dispare, pero da un poco igual si es posible ahorrar algunos KB, o si tenemos más cosas en el heap de las estrictamente necesarias.
Sin embargo, en nuestro caso sí que importa, y mucho.
Una de las cosas que teníamos en memoria y nos estorbaba eran las instrucciones ejecutables (bytecodes) de algunos métodos. Tenemos mucho código de preproceso, que se encarga de crear imágenes en memoria, leer datos de disco, ordenar listas, descomprimir datos, etc. y todo ese código sólo se ejecuta una vez, en el arranque del juego, por lo que nos lo queríamos quitar de encima una vez que se había ejecutado.
Pero... ¿cómo? Java (y mucho menos J2ME) no ofrece mecanismos para descargar de memoria cierta parte del código... bueno, no hay mecanismos directos, aunque no está todo perdido.
La solución que usamos pasaba por juntar todo ese código "de usar y tirar" en una única clase. Cuando se crea la primera instancia de esa clase, se meterá en el heap todos los bytecodes, y cuando se libere el último objeto de esa clase (y el recolector de basura entre en acción) todos esos bytecodes desaparecerán del heap. Sencillo, y lo mejor de todo es que funciona. Sacando gráficas de consumo de memoria de la aplicación (como la imagen de más arriba), se puede ver un par de descensos bruscos en el consumo de memoria. Se trata del momento justo en el que liberamos la última instancia de la clase de carga y forzamos la llamada al recolector.
Y es que, como se suele decir, el tamaño no importa, ¡¡excepto si programas juegos para móviles!!
El caso es que, mientras los distintos ponentes contaban sus historias, presentaban sus productos y demás, yo me iba dando cuenta de lo difícil y distinto que es programar juegos para móviles. Que si bases de datos relacionales, que si frameworks de mapeado R/O, arquitecturas basadas en servicios web, AJAX, OpenGL... y mientras tanto nosotros pegándonos con los desplazamientos de bits, o haciendo malabarismos para evitar esos dichosos arrays de 3 dimensiones que hacen que el heap explote.
Y es que, como bien decía Joel, aunque todos los programadores nos dediquemos a programar, los mundos en los que nos movemos son radicalmente distintos.
Os voy a contar un caso nuestro, que ya ha comentado Jaime por encima: nuestros juegos son bastante grandes, sobre todo teniendo en cuenta las capacidades de algunos móviles que soportamos. Por poneros en situación, El Cuarto Sello tiene 12 niveles y 9 tipos distintos de enemigos. Esto lo pone al nivel de muchos juegos de PC, pero metido en un móvil con 500 KB de memoria. Esto nos obliga a exprimir al máximo la memoria del teléfono, y como decía Jaime, hay muchas cosas que están

Si te dedicas a programar aplicaciones de escritorio o servidor, seguramente no te habrás parado a pensar si estás desperdiciando espacio en la memoria. Te bastará con que no haya memory leaks y que el consumo de memoria no se dispare, pero da un poco igual si es posible ahorrar algunos KB, o si tenemos más cosas en el heap de las estrictamente necesarias.
Sin embargo, en nuestro caso sí que importa, y mucho.
Una de las cosas que teníamos en memoria y nos estorbaba eran las instrucciones ejecutables (bytecodes) de algunos métodos. Tenemos mucho código de preproceso, que se encarga de crear imágenes en memoria, leer datos de disco, ordenar listas, descomprimir datos, etc. y todo ese código sólo se ejecuta una vez, en el arranque del juego, por lo que nos lo queríamos quitar de encima una vez que se había ejecutado.
Pero... ¿cómo? Java (y mucho menos J2ME) no ofrece mecanismos para descargar de memoria cierta parte del código... bueno, no hay mecanismos directos, aunque no está todo perdido.
La solución que usamos pasaba por juntar todo ese código "de usar y tirar" en una única clase. Cuando se crea la primera instancia de esa clase, se meterá en el heap todos los bytecodes, y cuando se libere el último objeto de esa clase (y el recolector de basura entre en acción) todos esos bytecodes desaparecerán del heap. Sencillo, y lo mejor de todo es que funciona. Sacando gráficas de consumo de memoria de la aplicación (como la imagen de más arriba), se puede ver un par de descensos bruscos en el consumo de memoria. Se trata del momento justo en el que liberamos la última instancia de la clase de carga y forzamos la llamada al recolector.
Y es que, como se suele decir, el tamaño no importa, ¡¡excepto si programas juegos para móviles!!
Etiquetas: j2me, programación