Esto puede ser fácil para juegos con un alcance bien definido, pero la pregunta es sobre los juegos de sandbox, donde el jugador puede crear y construir cualquier cosa .
Posibles técnicas:
- Use grupos de memoria con límite superior.
- Eliminar objetos que ya no son necesarios periódicamente.
- Asigne una cantidad adicional de memoria al principio para que pueda liberarse más tarde como mecanismo de recuperación. Yo diría que alrededor de 2-4 MB.
Es más probable que esto suceda en plataformas móviles / consolas donde la memoria generalmente es limitada a diferencia de su PC de 16 GB. Supongo que tiene control total sobre la asignación / desasignación de memoria y que no hay recolección de basura involucrada. Es por eso que etiqueto esto como C ++.
Tenga en cuenta que no estoy hablando del artículo 7 de C ++ eficaz "Prepárese para condiciones de falta de memoria" , aunque es relevante, me gustaría ver una respuesta más relacionada con el desarrollo del juego, donde generalmente tiene más control sobre lo que sucediendo.
Para resumir la pregunta, ¿cómo se prepara para las condiciones de falta de memoria para los juegos de sandbox, cuando se dirige a una plataforma con consola / móvil con memoria limitada?
fuente
Respuestas:
En general, no maneja la falta de memoria. La única opción sensata en un software tan grande y complejo como un juego es simplemente bloquear / afirmar / terminar en su asignador de memoria lo antes posible (especialmente en las compilaciones de depuración). Las condiciones de falta de memoria se prueban y manejan en algunos software de sistema central o software de servidor en algunos casos, pero no en otros lugares.
Cuando tienes un límite de memoria superior, solo asegúrate de nunca necesitar más que esa cantidad de memoria. Puede mantener un número máximo de NPC permitidos a la vez, por ejemplo, y simplemente dejar de generar nuevos NPC no esenciales una vez que se alcanza ese límite. Para los NPC esenciales, puede hacer que reemplacen los no esenciales o tener un grupo / límite separado para los NPC esenciales que sus diseñadores saben diseñar (por ejemplo, si solo puede tener 3 NPCsa esenciales, los diseñadores no pondrán más de 3 en un área / fragmento: buenas herramientas ayudarán a los diseñadores a hacer esto correctamente y las pruebas son esenciales, por supuesto).
Un sistema de transmisión realmente bueno también es importante, especialmente para los juegos de sandbox. No es necesario mantener todos los NPC y elementos en la memoria. A medida que te mueves por trozos del mundo, se introducirán nuevos fragmentos y fragmentos antiguos. Estos generalmente incluirán NPC y artículos, así como el terreno. El diseño y los límites de ingeniería en los límites de elementos deben establecerse teniendo en cuenta este sistema, sabiendo que a lo sumo X se conservarán trozos viejos y se cargarán proactivamente Y se cargarán trozos nuevos, por lo que el juego debe tener espacio para guardar todos los datos de los fragmentos X + Y + 1 en la memoria.
Algunos juegos intentan manejar situaciones de falta de memoria con un enfoque de dos pasos. Teniendo en cuenta que la mayoría de los juegos tienen muchos datos almacenados en caché técnicamente innecesarios (por ejemplo, los fragmentos anteriores mencionados anteriormente) y una asignación de memoria podría hacer algo como:
Esta es una medida de última parada para hacer frente a situaciones inesperadas en el lanzamiento, pero durante la depuración y las pruebas, probablemente debería bloquearse inmediatamente. No querrás tener que depender de este tipo de cosas (especialmente porque deshacerse de los cachés puede tener algunas consecuencias serias en el rendimiento).
También puede considerar descargar copias de alta resolución de algunos datos, por ejemplo, puede volcar los niveles de texturas mipmap de mayor resolución si se está quedando sin memoria GPU (o cualquier memoria en una arquitectura de memoria compartida). Sin embargo, esto generalmente requiere mucho trabajo arquitectónico para que valga la pena.
Tenga en cuenta que algunos juegos de sandbox muy ilimitados se pueden bloquear fácilmente, incluso en PC (recuerde que las aplicaciones comunes de 32 bits tienen un límite de 2-3 GB de espacio de direcciones, incluso si tiene una PC con 128 GB de RAM; un 64- bit OS y hardware permiten que más aplicaciones de 32 bits se ejecuten simultáneamente, pero no pueden hacer nada para que un binario de 32 bits tenga un espacio de direcciones más grande). Al final, tienes un mundo de juego muy flexible que necesitará un espacio de memoria ilimitado para ejecutarse en todos los casos o tienes un mundo muy limitado y controlado que siempre funciona perfectamente en la memoria limitada (o algo intermedio).
fuente
La aplicación generalmente se prueba en la plataforma objetivo con los peores escenarios y siempre estará preparado para la plataforma a la que se dirige. Idealmente, la aplicación nunca debería bloquearse, pero aparte de la optimización para dispositivos específicos, existen pocas opciones cuando se enfrenta una advertencia de poca memoria.
La mejor práctica es tener grupos previamente asignados y el juego utiliza desde el principio toda la memoria necesaria. Si su juego tiene un máximo de 100 unidades que tiene un grupo de 100 unidades y eso es todo. Si 100 unidades exceden los requisitos de memoria para un dispositivo específico, entonces puede optimizar la unidad para usar menos memoria o cambiar el diseño a un máximo de 90 unidades. No debe haber ningún caso en el que pueda construir cosas ilimitadas, siempre debe haber un límite. Sería muy malo usar un juego de sandbox
new
para cada instancia porque nunca puedes predecir el uso de mem y un bloqueo es mucho peor que una limitación.Además, el diseño del juego siempre debe tener en cuenta los dispositivos con el objetivo más bajo porque si basa su diseño con elementos "ilimitados", será mucho más difícil resolver los problemas de memoria o cambiar el diseño más adelante.
fuente
Bueno, puede asignar alrededor de 16 MiB (solo para estar 100% seguro) al inicio o incluso en el
.bss
momento de la compilación, y usar un "asignador seguro", con una firma comoinline __attribute__((force_inline)) void* alloc(size_t size)
(__attribute__((force_inline))
es un GCC /mingw-w64
atributo que fuerza la inserción de secciones críticas de código) incluso si las optimizaciones están deshabilitadas, aunque deberían estar habilitadas para los juegos) en lugar demalloc
intentarlovoid* result = malloc(size)
y si falla, suelte los cachés, libere la memoria de reserva (o dígale a otro código que use la.bss
cosa pero está fuera del alcance de esta respuesta) vaciar datos no guardados (guarde el mundo en el disco, si usa un concepto de fragmentos similar a Minecraft, llame a algo asísaveAllModifiedChunks()
). Luego, simalloc(16777216)
(al asignar estos 16 MiB nuevamente) falla (nuevamente, reemplácelo por análogo.bss
), finalice el juego y muestreMessageBox(NULL, "*game name* couldn't continue because of lack of free memory, but your world was safely saved. Try closing background applications and restarting the game", "*Game name*: out of memory", MB_ICONERROR)
o una alternativa específica de plataforma. Poniendolo todo junto:Puede usar una solución similar con
std::set_new_handler(myHandler)
dóndemyHandler
sevoid myHandler(void)
llama cuandonew
falla:fuente