Romper las reglas de la recolección de basura de Unity

Había una vez un programador de juegos de la unidad llamado Lancelot. Una muy apasionada, diría yo. Todavía no lo sabía, pero eventualmente enfrentaría el lado más oscuro de la recolección de basura de Unity.

imagen

Lancelot siempre estaba buscando títulos cada vez más grandes para trabajar. Y así trabajó duro para tener su gran oportunidad en la industria de los juegos.

No fue fácil, eso lo sabía.

Estos lugares en la industria del juego estaban y aún están reservados para una pequeña minoría de programadores de juegos. Y no estaba seguro de estar a la altura de todos modos.

Pero él persistió y continuó agudizando sus habilidades de programación.

Lancelot comenzó a trabajar en pequeños juegos. Quizás en algún momento, tendría la gran oportunidad que estaba buscando, pensó.

Pasaron los años hasta que tuvo la oportunidad que estaba esperando. Se le pidió que transfiriera un gran juego de realidad virtual a una plataforma móvil. Tan emocionado como estaba Lancelot, no podía dejar de preguntarse si era lo suficientemente bueno para la tarea. Fue desalentador pero aceptó el desafío. Sabía que solo podía salir de eso.

La mayor preocupación de Lancelot era la necesidad de mejorar enormemente el rendimiento del juego. Fue un doble desafío, de hecho. Tuvo que mejorar el rendimiento en un 20% para una plataforma significativamente menos potente .

Después de meses de trabajo ininterrumpido, finalmente logró optimizar el juego lo suficiente como para tener una base de rendimiento sólida como una roca.

Sin embargo, un problema inesperado estaba a la vuelta de la esquina ...

El generador de perfiles de la unidad le reveló una caída significativa de la velocidad de cuadros cada pocos segundos. Y eso le preocupaba porque eso no le permitiría enviar el juego. El lanzamiento del juego estaba en peligro. Eso lo hizo sentir completamente incómodo.

Basado en su experiencia previa, Lancelot rápidamente sospechó del recolector de basura . Después de todo, sabía que asignar memoria temporal en el juego con demasiada frecuencia podría causar estos picos de rendimiento. Al igual que el bote de basura en la cocina de todos, usted sabe que es hora de limpiarlo cuando alcanza el 80% de su capacidad.

Y así pasó días luchando contra las molestas asignaciones de memoria. Realizó todo tipo de optimizaciones que se le ocurrieron. Agrupaciones de objetos, almacenamiento en caché de datos, optimizaciones de estructura de datos ...

Pasar estos días optimizando lo llevó un poco por delante en el viaje de rendimiento. Lancelot estaba orgulloso de su trabajo, pero sus preocupaciones solo aumentaron cuando vio que el recolector de basura seguía funcionando cada 15 segundos.

Jugar el juego en realidad virtual con estas caídas de rendimiento de alguna manera haría que las personas se vean pálidas.

"¿Cómo podría estar pasando eso?", Se preguntó.

Con más paciencia y excavación, Lancelot descubrió una segunda fuente de asignaciones de memoria que no había visto antes. Esos sucedieron en una biblioteca de terceros .

Echó un vistazo y pronto se dio cuenta de que estaba en la peor posición: la biblioteca era de código cerrado. No solo eso, también trató de usar el recolector de basura incremental de Unity, pero no podía pagar el precio de su rendimiento.

Lancelot se estaba quedando sin opciones.

Se sentía desesperado pero logró mantener la calma. Ha estado en situaciones peores después de todo.

Podía realizar ingeniería inversa en la biblioteca y hacer las optimizaciones de asignación de memoria él mismo. El problema era que la licencia no permitía tales cosas. Y él era demasiado joven para ir a la cárcel.

La segunda opción que consideró fue preasignar mucha memoria en el montón. Sabía que la unidad desencadenaba el proceso de recolección de basura cuando el uso del montón alcanzaba un cierto porcentaje. Por lo tanto, aumentar el montón debería darle más tiempo entre las recolecciones de basura.

Lamentablemente, eso todavía no fue suficiente.

Lentamente se sintió como si no tuviera control sobre la situación. Fue duro, pero de nuevo, él persistió .

Entonces a Lancelot se le ocurrió una idea loca . ¿Qué pasa si deshabilita la recolección de basura por completo? ¿Era eso posible? Sintió en sus huesos lo arriesgada que era esa idea. No quería agregar la posibilidad de que el juego se bloquee en puntos impredecibles. La última vez que lo revisó, eso no fue divertido para los jugadores. Tal vez los tiempos cambiaron, pero más vale prevenir que curar.

Además de eso, le preocupaba retrasar el lanzamiento del juego. No quería que sus jugadores se perdieran este título para Navidad. Recordó lo divertido que era jugar EverQuest durante estas vacaciones. No le quitaría eso a los jugadores.

Llegado a este punto, no tenía otra opción que desactivar el recolector de basura.

Entró en modo de investigación y descubrió que podía deshabilitar manualmente la recolección de basura . Realizó docenas de experimentos para ver cuánto tiempo duraría el juego sin quedarse sin memoria. Hizo todo tipo de pruebas para estresar el sistema. Al hacer clic en todas partes, caminar y saltar, cambiar entre diferentes aplicaciones.

Los números comenzaron a llegar en su hoja de cálculo: 25 minutos, 28 minutos, 30 minutos ... También notó cómo el uso del montón aumentó con el tiempo para asegurarse de que nunca excedería un presupuesto seguro.

Con esos números, Lancelot estableció un generoso margen seguro y preparó un prototipo . Corría la recolección de basura manualmente durante las pantallas de carga y cada pocos minutos.

Tenía esperanza de nuevo.

Cortésmente le pidió a QA que revisara el juego docenas de veces.

La memoria siempre estuvo dentro del presupuesto. No se bloquea. Sin efectos secundarios.

Este largo viaje lo llevó al punto donde pudo enviar el juego.

¿Y adivina qué? Cientos de jugadores ahora lo disfrutan durante el período navideño.

Al principio, no estaba cómodo con esta solución. Fue un movimiento arriesgado y él lo sabía. Pero se las arregló para lograrlo.

Lancelot aprendió a sentirse cómodo con lo incómodo . Aprendió a ser más pragmático . Porque hay momentos en que un programador tiene que serlo.

¿Algo de la historia te suena? Si es así, su intuición probablemente sea correcta.

Ese programador era yo.

Para las veces que lo necesite, así es como puede administrar el recolector de basura:

Ese fragmento de código le muestra cómo deshabilitar las recolecciones de basura automáticas. Ejecuta el proceso de GC manualmente cada minuto y posiblemente durante las transiciones de pantalla (fundido a negro).

Tenga en cuenta sus posibles efectos secundarios:

  • Accidentes : si no juegas lo suficientemente seguro, te quedarás sin memoria. Peor aún, el sistema operativo puede matar tu juego cuando cambias de aplicación
  • Tiempos de recolección de basura más largos : aumentar el montón hará que las futuras recolecciones de basura sean más lentas

Si necesita producir cantidades generosas de basura, aquí hay un método sencillo que funcionará:

public class GenerousGarbageCreator : MonoBehaviour { [SerializeField] private int garbageCreationRate = 1024; private static int[] _garbage; void Update() { _garbage = new int[garbageCreationRate]; } } 

Esto es lo que obtendrás en el generador de perfiles:

imagen
Recolección de basura de Unity: disparador manual basado en el tiempo

Ahí ves un uso creciente de la memoria. El uso creciente del montón se resalta como "mono". Afortunadamente para nosotros, estamos ejecutando el recolector de basura manual cada 3 segundos.

Puede ver claramente este ciclo de generación de basura en el gráfico del generador de perfiles. Para aquellos desarrolladores de juegos que estudiaron física, es posible que la reconozcan como una forma de onda de diente de sierra.

Si desea el código fuente de este proyecto, ya sabe dónde encontrarlo (spoiler: aquí).

Para optimizaciones de memoria más generales, puede estar interesado en Unity Addressables. Con los direccionables puede reducir el uso total de memoria para que pueda desencadenar la recolección de basura con menos frecuencia. A su vez, esto reducirá los picos de rendimiento que experimentarán tus jugadores.

Tengo muchas ganas de trabajar con todos ustedes en 2020.
Rubén

Source: https://habr.com/ru/post/484710/


All Articles