Skyrim y la gestión de memoria

Un programador nos explica con todo lujo de detalles el origen del polémico bug.

Como algunos de vds. ya habrán leído en el último artículo de Digital Foundry, la versión para PS3 de Skyrim (y en menor medida las demás, pero especialmente en la consola de Sony) adolece de un problema francamente molesto: cuanto más tiempo llevas jugando, cuanto más pesa el archivo de tu partida guardada y peor es el rendimiento del juego.

Antes que nada, y para entender plenamente el problema de Skyrim, es necesario que me ponga un poco técnico y explique de forma sencilla en qué consiste la gestión de memoria en un programa. Tranquilos, no es necesario saber programar para entenderlo y voy a hacerlo lo más accesible que pueda. Esto significa que si me lee algún programador igual tuerce un poco el morro al leer algunas de las licencias que voy a tomarme, pero espero que tenga en cuenta que este texto está especialmente dirigido a profanos en la materia y hay que explicarlo bien claro.

Imaginense por un momento un programa que simplemente efectúa una suma. Algo tan sencillo como coger dos números y sumarlos.

Este proceso implica varias cosas. En primer lugar, que se necesitarán tres números a lo largo de la ejecución del programa: dos para los sumandos y uno para el resultado. Todos los lenguajes de programación del mundo (o casi, pero para el caso asumiremos que es así) siguen la misma metodología, reservando un espacio de memoria para esos números. El espacio de memoria es algo dinámico, lo que significa que se puede reservar la cantidad de memoria que el programador considere oportuno. Si se reserva poca memoria para el volumen de datos que se intenta almacenar, la memoria sufrirá lo que se conoce como "buffer overflow", un desbordamiento de memoria, y el programa dejará de funcionar.

Así que se suele aceptar como una buena práctica de programación el reservar la mayor cantidad posible (y razonable, que tampoco hay que pasarse) de memoria para cualquier variable. Digamos que reservar memoria es planificar cómo de grande tiene que ser un bolsillo para guardar lo que quiera guardar en él, y a partir de eso crear un bolsillo donde pueda guardar todas mis cosas tranquilamente sin peligro de que se me rompa por llenarlo demasiado.

La cantidad de memoria reservada para el ejemplo de la calculadora es ínfima, no creo que en realidad llegara a un kilobyte en total. Pero si hacemos trampas podemos imaginar que cada número de la suma ocupa doscientos megabytes de memoria. Tres números ocuparían seiscientos megabytes. Si nuestra memoria es de un gigabyte eso significa que el programa ocupará, en el momento de máximo consumo de memoria, más de la mitad de la que tenemos disponible.

Ahí entra en juego el segundo concepto que manejaremos en este artículo: la destrucción de memoria. En realidad la memoria no se destruye, porque uno no coge su RAM y le pega fuego, sino que simplemente se libera. No se vacía, sino que se marca como disponible para que el sistema disponga libremente de ella.

Una partida 'virgen' de Skyrim frente a una tras 65 horas de juego. Los problemas son evidentes y francamente molestos.

Nuestro programa de sumas sólo se ha ejecutado una vez y ya ha ocupado seiscientos megabytes de memoria. Si lo ejecutamos otra vez no tendrá suficiente memoria disponible y ésta se desbordará, provocando un problema gordo. Lo que se hace siempre en estos casos es liberar la memoria utilizada una vez que ya no es necesaria. En el caso de la calculadora, lo normal sería liberarla una vez ha impreso por pantalla el resultado de la suma. De esta forma, cuando volvamos a ejecutar el programa tendremos disponible todo el gigabyte de memoria y no sólo los insuficientes cuatrocientos megabytes.

Este sistema es parecido a formatear un disco: cuando uno hace un formateo normal, sin reescritura, lo que hace es indicarle al sistema que todos los clústers del disco están disponibles para escritura. Salvo formateos que reescriben todo el disco (y que acortan sensiblemente su vida útil, por cierto), un formateo normal y corriente no elimina datos, sino que permite que se escriba encima. De ahí que se pueda recuperar información tras un formateo usando una herramienta de recuperación: la información sigue ahí (salvo si ya se ha escrito encima), solo que el sistema operativo muestra ese espacio como libre y vacío.

Si me han seguido hasta aquí, entenderán que un programa crea memoria y que es necesario que esa memoria se libere cuando ya no se utilice. Es la piedra angular de la programación de software.

Solo que en Bethesda parecen creer que no.

En este enlace se pueden leer las respuestas del desarrollador jefe de Fallout: New Vegas a las preguntas que los usuarios le hicieron a propósito del problema del rendimiento en su juego:

Digamos que yo, como diseñador, coloco una criatura en un area. Dispongo todas las estadísticas y el equipo de la criatura y lo guardo en el archivo principal FalloutNV.esm, que es el que se carga en el juego. Tú, el jugador, llegas a ese área y le pegas un tiro al personaje. Despojas su equipo y le metes una pala en su inventario porque eres así de raro.

El juego necesita una manera de determinar a) su posición, b) su salud, c) su inventario y d) más cosas que han cambiado en el personaje. Lo hace al marcar los campos que han cambiado y almacenando los nuevos valores para posteriores búsquedas.

Cuando cargas el juego guardado se cargan todos los cambios del juego. Cuando se carga un objeto individual se le aplican los cambios almacenados a esos objetos. Así, cuando vuelves a ese área por la que pasaste hace dos noches, el personaje sigue tirado donde lo dejaste, desnudo y con una pala en su inventario.

Los bits de memoria individual son pequeños, pero hay miles y miles de objetos en F:NV, y cada uno contiene numerosos campos de datos que podrían cambiar en tu partida guardada. Simplemente se van sumando.

Esto es una chapuza, simple y llanamente, un esperpento. Cualquier programador se echará las manos a la cabeza al leer esto. Es una locura, un error de diseño, de concepción y de programación tan salvaje que creo que sólo el affaire de Sony con la seguridad de la PS3, y su famoso número aleatorio que no era tal, se le puede comparar. Es el error más grande de la generación, y posiblemente más gordo incluso que eso.

Con esas palabras, ni más ni menos que de puño y letra del desarrollador en jefe de Fallout New Vegas, está diciendo que en su juego no se destruye la memoria. Así de sencillo y terrible. Que la memoria destinada a su juego (y a Skyrim, para el caso) nunca disminuye, sino que sólo puede aumentar. Es como si al usar nuestro programa de sumas no se liberara la memoria para posteriores usos. En ese caso, el programa no se podría usar más de una vez. La memoria se desbordaría si no la liberasemos.

Fallout 3, Fallout New Vegas y Skyrim no la liberan.

Siguiendo el ejemplo del personaje al que tan vilmente asesinas, cualquier programador con dos dedos de frente sobreescribiría los valores antiguos de salud, posición, inventario y demás valores que hayan cambiado por los nuevos, eliminando esos valores anteriores de la memoria y haciendo que ésta quedara disponible para escritura. Y luego los guardaría en la partida salvada. ¿Qué necesidad hay de mantener los antiguos valores, los de una criatura viva, en la actualidad, cuando la criatura está muerta y looteada, y con una pala en el inventario? Ninguna. Esos valores ya no son útiles para el juego, no se deben volver a usar en la partida en curso y, por tanto, deben desaparecer de la memoria. Es más, ni siquiera deberían usarse al cargar una partida guardada.

Solo que no se hace así.

Soy incapaz de entender por qué se ha hecho de ese modo, pero el caso es que en Bethesda no sólo han cometido un error que yo, un triste técnico superior, sabe que no debe cometer nunca, sino que, además, es un error imposible de arreglar con un simple parche. No se puede modificar la gestión de memoria de un programa sin una reescritura tan profunda del código que, al final, implicaría tirarlo a la basura y volver a escribir buena parte de él. El código de los juegos de Bethesda es, a día de hoy, una chapuza increíble y sin arreglo, y todos los juegos desarrollados con esa tecnología tendrán exactamente el mismo problema: cuantas más horas lleves, peor rendimiento tendrán porque más memoria habrá ocupado. Y esa memoria, como ya hemos dicho, nunca se vacía; sólo se llena.

Cuanto más juegues, más cambios habrás introducido en el juego, por puro avance, y más memoria habrán consumido esos cambios. Cuanto más juegues, peor. El problema no hará más que agravarse.

La diferencia de rendimiento entre las distintas versiones se justifica en cierta forma teniendo en cuenta las diferencias en la arquitectura. PS3 tiene la memoria para gráficos separada de la memoria para el sistema, mientras que en 360 y pc es la misma para ambos. Lo que significa que, si bien el total puede ser el mismo, a la hora de la verdad en PS3 sólo dispones de 256 Mb de memoria para algo en lo que en 360 dispones del doble, y en pc del orden de ocho veces más como mínimo. Lo que significa, simple y llanamente, que la memoria de PS3 se llena antes y empieza a dar problemas mucho antes que en las demás versiones.

¿Significa que en las otras versiones no pasa? Sí, sí que pasa. Solo que se nota menos, o incluso más tarde (me refiero a tarde en cuanto a horas de juego) que en sus contrapartidas de otras plataformas. ¿Significa que es culpa de la arquitectura de PS3? En absoluto. El error es del código del juego, no del soporte.

El motor (no confundir con motor gráfico; me refiero al código del juego, el que lo hace todo, incluyendo cargar las texturas) de Skyrim es una versión mejorada del motor del Fallout 3 y el Fallout: New Vegas, pero cojea del mismo pie. Como he dicho antes, la única solución real al problema era reescribir el código entero y gestionar bien la memoria. No se ha hecho así, por lo que Skyrim tiene el mismo problema que tenían Fallout 3 y Fallout: New Vegas.

No puedo ni siquiera empezar a comprender como se ha podido cometer un error de este calibre. Es como diseñar un coche al que no se le puede cambiar ninguna pieza, al que no puedes cambiarle ni los neumáticos ni un triste filtro de aceite, y que se acaba estropeando definitivamente sin posibilidad de arreglo porque no puedes ponerle un repuesto. Pues es exactamente el mismo error, solo que aplicado a un videojuego que ha vendido millones de copias desde el día del lanzamiento.

Si yo fuera el dueño de uno de esos millones de copias ahora mismo estaría realmente cabreado.

Comentarios (78)

Ya no se pueden publicar más comentarios. ¡Gracias por tu aportación!