Hero background image

Perfilar y analizar el uso de memoria con las herramientas de perfilado de memoria de Unity

Esta página proporciona información sobre dos herramientas para analizar el uso de memoria en su aplicación en Unity: El paquete Memory Profiler y el módulo Memory Profiler.
Para tu comodidad, tradujimos esta página mediante traducción automática. No podemos garantizar la precisión ni la confiabilidad del contenido traducido. Si tienes alguna duda sobre la precisión del contenido traducido, consulta la versión oficial en inglés de la página web.
Guía y tutorial de Memory Profiler | Unity

-

Al perfilar y perfeccionar el rendimiento de su juego para una amplia gama de plataformas y dispositivos, puede expandir su base de jugadores y aumentar sus posibilidades de éxito.

-

La información aquí se extrae de la Guía definitiva para perfilar juegos de Unity (edición Unity 6), un libro electrónico creado por expertos externos e internos de Unity en desarrollo de juegos, perfilado y optimización.

¿Qué es el perfilado de memoria?

El perfilado de memoria está en gran medida no relacionado con el rendimiento en tiempo de ejecución, pero es útil para probar contra las limitaciones de memoria de la plataforma de hardware o si tu juego se está bloqueando. También puede ser relevante si deseas mejorar el rendimiento de la CPU/GPU haciendo cambios que realmente aumenten el uso de memoria.

Hay dos formas de analizar el uso de memoria en tu aplicación en Unity:

- El Módulo del Memory Profiler: Este es un módulo de perfilador integrado que te brinda información básica sobre dónde usa memoria tu aplicación en el perfilador regular.

- El Memory Profiler: Esta es una herramienta dedicada disponible como un paquete de Unity que puedes agregar a tu proyecto. Agrega una ventana adicional del Memory Profiler al Editor de Unity, que luego puedes usar para analizar el uso de memoria en tu aplicación con aún más detalle. Puedes almacenar y comparar instantáneas para encontrar filtraciones de memoria, o ver el diseño de la memoria para encontrar problemas de fragmentación. Cubriré esto con más detalle más adelante en esta guía y mantendré el enfoque aquí en las consideraciones generales que necesitas tener en cuenta.

Ambas herramientas te permiten monitorear el uso de memoria, localizar áreas de una aplicación donde el uso de memoria es mayor de lo esperado, y encontrar y mejorar la fragmentación de memoria.

El paquete del Memory Profiler es una herramienta que puedes usar para inspeccionar el uso de memoria de tu aplicación de Unity y del Editor de Unity.
El paquete del Memory Profiler es una herramienta que puedes usar para inspeccionar el uso de memoria de tu aplicación de Unity y del Editor de Unity.

Comprender y definir un presupuesto para la memoria

Entender y presupuestar las limitaciones de memoria de tus dispositivos objetivo es crítico para el desarrollo multiplataforma. Al diseñar escenas y niveles, necesitas ceñirte al presupuesto de memoria que se establece para cada dispositivo objetivo. Al establecer límites y pautas, puedes asegurarte de que tu aplicación funcione bien dentro de los confines de las especificaciones de hardware de cada plataforma.

Puedes encontrar las especificaciones de memoria del dispositivo en documentación del desarrollador.

También puede ser útil establecer presupuestos de contenido en torno a la complejidad de mallas y shaders, así como para la compresión de texturas. Todo esto influye en cuánto se asigna de memoria. Estas cifras de presupuesto pueden ser referenciadas durante el ciclo de desarrollo del proyecto.

Determinar los límites de RAM física

Dado que cada plataforma tiene un límite de memoria, su aplicación necesitará un presupuesto de memoria para cada uno de sus dispositivos objetivo. Utilice el perfilador de memoria para ver una instantánea capturada de su uso de memoria. La instantánea de Recursos de Hardware (ver imagen a continuación) muestra los tamaños de Memoria de Acceso Aleatorio Física (RAM) y Memoria de Acceso Aleatorio de Video (VRAM). Esta cifra no tiene en cuenta el hecho de que no todo ese espacio podría estar disponible para usar. Sin embargo, proporciona una cifra aproximada útil para comenzar a trabajar.

Es una buena idea cruzar las especificaciones de hardware para las plataformas objetivo, ya que las cifras mostradas aquí pueden no siempre mostrar el panorama completo. El hardware del kit de desarrollo a veces tiene más memoria, o puede que esté trabajando con hardware que tiene una arquitectura de memoria unificada.

La instantánea de Recursos de Hardware muestra los números de RAM y VRAM del dispositivo sobre los cuales se tomó la instantánea.
La instantánea de Recursos de Hardware muestra los números de RAM y VRAM del dispositivo sobre los cuales se tomó la instantánea.

Determinar la especificación mínima de RAM

Identifique el hardware con la especificación de RAM más baja para cada plataforma que soporte, y use esto para guiar su decisión sobre el presupuesto de memoria. Recuerde que no toda esa memoria física podría estar disponible para usar. Por ejemplo, una consola podría tener un hipervisor en funcionamiento para soportar juegos más antiguos que podrían usar parte de la memoria total. Piense en un porcentaje (por ejemplo, el 80% del total) para usar como equipo dependiendo de su escenario específico. Para plataformas móviles, también podría considerar dividir en múltiples niveles de especificaciones para soportar mejor calidad y características para aquellos con dispositivos de gama alta.

Considere los presupuestos por equipo para equipos más grandes

Una vez que tenga un presupuesto de memoria definido, considere establecer presupuestos de memoria por equipo. Por ejemplo, sus artistas de entorno obtienen una cierta cantidad de memoria para usar en cada nivel o escena que se carga, el equipo de audio obtiene asignación de memoria para música y efectos de sonido, y así sucesivamente. Si bien esto puede parecer rígido, piénselo como pautas para informar las decisiones creativas que se están tomando frente al costo de los recursos.

Es importante ser flexible con los presupuestos a medida que avanza el proyecto. Si un equipo se mantiene por debajo del presupuesto, asigne el excedente a otro equipo si puede mejorar las áreas del juego que están desarrollando.

Una vez que decidas y establezcas presupuestos de memoria para tus plataformas objetivo, el siguiente paso es utilizar herramientas de perfilado para ayudarte a monitorear y rastrear el uso de memoria en tu juego, lo que te permitirá tomar decisiones informadas y realizar acciones según sea necesario.

Algunos consejos para el perfilado de memoria

Para determinar a un alto nivel cuándo el uso de memoria comienza a acercarse a los presupuestos de la plataforma, utiliza el siguiente cálculo de "servilleta":

Memoria Usada del Sistema (o Memoria Total Reservada si Memoria Usada muestra 0) + un margen aproximado de memoria no rastreada / memoria total de la plataforma

Cuando esta cifra comienza a acercarse al 100% del presupuesto de memoria de tu plataforma, utiliza el paquete Memory Profiler para averiguar por qué.

En Unity 6, muchas de las características del módulo Memory Profiler son reemplazadas por el paquete Memory Profiler, pero aún puedes usar el módulo para complementar tus esfuerzos de análisis de memoria. Por ejemplo:

- Para detectar asignaciones de GC: Aunque estos aparecen en el módulo, son más fáciles de rastrear utilizando Project Auditor o Profiling Profundo.

- Para ver rápidamente el tamaño Usado/Reservado del montón

- Análisis de memoria de shaders

- Utiliza la vista Detallada en el módulo Memory Profiler para profundizar en los árboles de memoria más altos y averiguar qué está utilizando más memoria.

Aquí hay más recursos para ayudarte a explorar casos de uso adicionales y características del Unity Profiler:

- Resumen del Profiler en el manual de Unity

- Introducción al perfilado en Unity

- Cómo perfilar y optimizar un juego

Normalmente querrás perfilar utilizando un sistema de desarrollador potente con mucha memoria disponible (el espacio para almacenar grandes instantáneas de memoria o cargar y guardar esas instantáneas rápidamente es importante).

El perfilado de memoria es una bestia diferente en comparación con el perfilado de CPU y GPU porque puede incurrir en un sobrecosto adicional de memoria. Es posible que necesites perfilar la memoria en dispositivos de gama alta (con más memoria), pero ten cuidado específicamente con el límite de presupuesto de memoria para la especificación de objetivo de gama baja.

Configuraciones como niveles de calidad, niveles gráficos y variantes de AssetBundle pueden tener un uso de memoria diferente en dispositivos más potentes. Con eso en mente, aquí hay algunos detalles a tener en cuenta para obtener lo máximo del perfilado de memoria:

- La calidad y la configuración gráfica pueden afectar el tamaño de las texturas de renderizado utilizadas para los mapas de sombras.

- La escala de resolución puede afectar el tamaño de los búferes de pantalla, las texturas de renderizado y los efectos de post-procesamiento.

- La configuración de texturas puede afectar el tamaño de todas las texturas.

- El LOD máximo puede afectar modelos y más.

Si tienes variantes de AssetBundle como una versión HD (Alta Definición) y una versión SD (Definición Estándar), y eliges cuál usar según las especificaciones de tu dispositivo objetivo, podrías obtener diferentes tamaños de activos según el dispositivo que estés perfilando.

- La resolución de pantalla de tu dispositivo objetivo afectará el tamaño de las texturas de renderizado utilizadas para los efectos de post-procesamiento.

- La API gráfica soportada de un dispositivo podría afectar el tamaño de los shaders según qué variantes de ellos soporte (o no soporte).

- Un sistema escalonado que utiliza diferentes configuraciones de calidad y gráficos, así como variantes de AssetBundle, es una excelente manera de poder dirigirse a una gama más amplia de dispositivos.

Por ejemplo, puedes cargar una versión HD de un AssetBundle en un dispositivo móvil de 4GB, y una versión SD en un dispositivo de 2GB. Sin embargo, ten en cuenta las variaciones anteriores en el uso de memoria y asegúrate de probar ambos tipos de dispositivos, así como dispositivos con diferentes resoluciones de pantalla o APIs gráficas soportadas.

Nota: El Editor de Unity generalmente mostrará siempre una huella de memoria más grande debido a objetos adicionales que se cargan desde el Editor y el Profiler. Además, la huella de memoria de las texturas es mayor ya que todas están forzadas a tener habilitada la lectura/escritura en el Editor.

El módulo Memory Profiler te permite ver fácilmente cuánta memoria has asignado al sistema.
El módulo Memory Profiler te permite ver fácilmente cuánta memoria has asignado al sistema.

El paquete Memory Profiler

El paquete Memory Profiler puede ayudarte a entender y optimizar el uso de memoria de tu proyecto. Te permite capturar 'instantáneas' de la memoria de tu aplicación en momentos específicos, tanto dentro del Editor de Unity como en las compilaciones de Player en tu dispositivo objetivo.

Las instantáneas proporcionan un desglose completo de cómo se está utilizando la memoria, mostrando las asignaciones a lo largo del motor. Esto te ayuda a identificar fuentes de uso excesivo o innecesario de memoria, rastrear fugas de memoria e inspeccionar problemas como la fragmentación de la memoria.

Después de instalar el paquete Memory Profiler, ábrelo a través de Ventana > Análisis > Memory Profiler.

La barra de menú superior del Memory Profiler te permite cambiar el objetivo de selección del jugador y capturar o importar instantáneas. El menú desplegable de selección de objetivo en la esquina superior izquierda te permite perfilar la memoria directamente en tu hardware objetivo conectando el Memory Profiler al dispositivo remoto. Ten en cuenta que el perfilado en el Editor de Unity te dará cifras inexactas debido a los costos adicionales que añade el Editor y otras herramientas.

Cambia la selección del jugador y captura o importa instantáneas de memoria.
Cambia la selección del jugador y captura o importa instantáneas de memoria.

Componente de instantáneas

En el lado izquierdo de la ventana del Memory Profiler se encuentra el componente Instantáneas. Utiliza esto para gestionar y abrir o cerrar instantáneas de memoria guardadas. El componente de Instantánea proporciona dos vistas, Instantánea Única y Comparar Instantánea.

Similar al Analizador de Perfiles, el Memory Profiler te permite cargar y comparar dos instantáneas de memoria lado a lado. Utiliza esta comparación para rastrear el crecimiento de la memoria a lo largo del tiempo, analizar el uso entre escenas o identificar posibles fugas de memoria.

El Memory Profiler tiene una serie de pestañas en la ventana principal que te permiten profundizar en las instantáneas de memoria, siendo las clave Resumen, Objetos de Unity y Todo de la Memoria. Veamos cada una de estas opciones en detalle.

Puedes gestionar múltiples instantáneas de memoria.
Puedes gestionar múltiples instantáneas de memoria.

La pestaña Resumen

La pestaña Resumen te da una instantánea de alto nivel del uso de memoria de tu proyecto en el momento en que se tomó una captura de memoria. Es perfecta para cuando deseas una visión rápida e informativa sin profundizar en un análisis detallado.

Esta vista resalta métricas clave y puede ayudarte a detectar rápidamente posibles problemas de memoria o patrones de uso inesperados. Es especialmente útil al comparar instantáneas o depurar el uso de memoria a lo largo del tiempo. Veamos algunas de sus secciones clave.

Sugerencias: En el panel derecho (ver imagen abajo), encontrarás información contextual útil sobre tu instantánea. Estos pueden alertarte sobre posibles problemas o guiarte en la interpretación de resultados.

Uso de memoria en el dispositivo: Esto muestra la huella de la aplicación en la memoria física. Incluye todas las asignaciones de Unity y no Unity residentes en la memoria en el momento de la captura.

Distribución de memoria asignada: Esta vista visualiza cómo se distribuye la memoria asignada en diferentes categorías de memoria.

Nota la barra de memoria No rastreada*. Corresponde a la memoria que Unity no rastrea a través de su sistema de gestión de memoria. Tales asignaciones pueden provenir de complementos nativos y controladores. Utiliza el perfilador específico de la plataforma para analizar el uso de memoria No rastreada para tu dispositivo objetivo.

Utilización de la pila administrada: En esta vista, obtendrás un desglose de la memoria que gestiona la VM de scripting de Unity, que incluye la memoria de la pila administrada utilizada para objetos administrados, espacio vacío de la pila que podría haber sido utilizado anteriormente por objetos o haber sido reservado durante la última expansión de la pila, y memoria utilizada por la propia máquina virtual.

Principales categorías de objetos de Unity: Esto muestra qué tipos de objetos de Unity utilizan más memoria en la instantánea (por ejemplo, Texture2D, malla, GameObject).

La pestaña Resumen muestra una descripción general de la memoria en el momento en que se capturó la instantánea.
La pestaña Resumen muestra una descripción general de la memoria en el momento en que se capturó la instantánea.

La pestaña Objetos

La pestaña de objetos de Unity muestra cualquier objeto de Unity que haya asignado memoria, cuánta memoria nativa y administrada utiliza el objeto, y el total combinado. Utiliza esta información para identificar áreas donde puedes eliminar entradas de memoria duplicadas o para encontrar qué objetos utilizan más memoria. Y a través de la barra de búsqueda, puedes encontrar las entradas en la tabla que contienen el texto que ingresas.

Por defecto, la tabla lista todos los objetos relevantes por Tamaño Asignado en orden descendente. Puedes hacer clic en el nombre de un encabezado de columna para ordenar la tabla por esa columna o para cambiar si la columna se ordena en orden ascendente o descendente.

Utiliza esto a tu favor al optimizar el uso de memoria y al intentar empaquetar la memoria de manera más eficiente para plataformas de hardware donde los presupuestos de memoria son limitados.

La pestaña de Objetos de Unity te permite profundizar en el uso de memoria de instantáneas capturadas con alta granularidad.
La pestaña de Objetos de Unity te permite profundizar en el uso de memoria de instantáneas capturadas con alta granularidad.

Técnicas y flujos de trabajo de perfilado de memoria

Comienza analizando una instantánea del perfilador de memoria para identificar áreas de alto uso de memoria. Una vez que captures o cargues una instantánea del perfilador de memoria, utiliza la pestaña de Objetos de Unity para inspeccionar las categorías, ordenadas de mayor a menor en tamaño de huella de memoria.

Los activos del proyecto son a menudo los mayores consumidores de memoria. Usando el modo Tabla, localiza texturas, mallas, clips de audio, texturas de renderizado, variantes de sombreadores y búferes preasignados. Estos son a menudo buenos candidatos para comenzar a optimizar el uso de memoria. El Auditor de Proyecto es una gran herramienta complementaria aquí, ya que puede proporcionar algunas recomendaciones sobre cómo reducir el uso de memoria para los activos (asegurarse de que el activo esté configurado correctamente en el Inspector de Configuraciones de Importación es un buen punto de partida).

Localizando fugas de memoria

Una fuga de memoria es una situación en la que los activos, objetos o recursos no utilizados no se liberan adecuadamente de la memoria. Esto puede llevar a un uso de memoria que aumenta progresivamente y a problemas de rendimiento o bloqueos.

Una fuga de memoria típicamente ocurre cuando:

- Un objeto no se libera manualmente de la memoria a través del código.

- Un objeto permanece en la memoria de manera no intencionada porque otro objeto aún tiene una referencia a él.

El perfilador de memoria tiene un modo de Comparar Instantáneas que puede ayudar a encontrar fugas de memoria al comparar dos instantáneas durante un marco de tiempo específico. Esta comparación puede revelar objetos que persisten en la memoria cuando deberían ser desalojados.

Un escenario frecuente para fugas de memoria en juegos de Unity es después de descargar una escena. Los objetos de la escena descargada pueden no ser recolectados correctamente si aún existen referencias a ellos.

Localizando asignaciones de memoria recurrentes a lo largo de la vida de la aplicación

A través de comparación diferencial de múltiples instantáneas de memoria, puedes identificar la fuente de las asignaciones de memoria continuas durante la vida útil de la aplicación.

Las siguientes secciones proporcionan algunos consejos para ayudar a identificar las asignaciones de heap administradas en tus proyectos.

Compara dos instantáneas para ver las diferencias.
Compara dos instantáneas para ver las diferencias.

Asignaciones gestionadas como se muestra en el módulo Memory Profiler

El módulo Memory Profiler en el Unity Profiler representa las asignaciones administradas por fotograma con una línea roja. Esto debería ser 0 la mayor parte del tiempo, por lo que cualquier aumento en esa línea indica fotogramas que deberías investigar para asignaciones administradas.

Cualquier aumento observado en la recolección de basura asignada en el marco te brinda información para investigar las asignaciones administradas.
Cualquier aumento observado en la recolección de basura asignada en el marco te brinda información para investigar las asignaciones administradas.

Vista de Timeline en el módulo de CPU Usage Profiler

La vista de Timeline en el módulo CPU Usage Profiler muestra asignaciones, incluidas las administradas, en color rosa, lo que facilita enfocarse en ellas.

Las asignaciones administradas se ven como marcadores de color rosado en la vista de Timeline.
Las asignaciones administradas se ven como marcadores de color rosado en la vista de Timeline.

Pilas de llamadas de asignación

Las pilas de llamadas de asignación proporcionan una forma rápida de descubrir asignaciones de memoria administradas en tu código. Estas proporcionarán el detalle de la pila de llamadas que necesitas con menos sobrecarga en comparación con lo que normalmente añadiría el perfilado profundo, y se pueden habilitar sobre la marcha utilizando el Profiler estándar.

Las pilas de llamadas de asignación están deshabilitadas por defecto en el Profiler. Para habilitarlas, haz clic en el botón Pilas de Llamadas en la barra de herramientas principal de la ventana del Profiler. Cambia la vista Detalles a Datos Relacionados.

Nota: Si estás utilizando una versión más antigua de Unity (anterior al soporte de pilas de llamadas de asignación), entonces el perfilado profundo es una buena manera de obtener pilas de llamadas completas para ayudar a encontrar asignaciones administradas.

Las muestras de GC.Alloc seleccionadas en la Jerarquía o Jerarquía Cruda ahora contendrán sus pilas de llamadas. También puedes ver las pilas de llamadas de las muestras de GC.Alloc en la información sobre herramientas de selección en Timeline.

Activar las pilas de llamadas de asignación en el Profiler te permitirá rastrear el origen de la pila de llamadas en las asignaciones administradas.
Activar las pilas de llamadas de asignación en el Profiler te permitirá rastrear el origen de la pila de llamadas en las asignaciones administradas.

Vista de Hierarchy en CPU Usage Profiler

La vista de Jerarquía en el CPU Usage Profiler te permite hacer clic en los encabezados de columna para usarlos como criterios de ordenación. Ordenar por GC Alloc es una excelente manera de enfocarse en esos.

Utilizar la vista de Jerarquía en el módulo CPU Usage Profiler es una excelente manera de filtrar las asignaciones administradas y enfocarse en las que necesites.
Utilizar la vista de Jerarquía en el módulo CPU Usage Profiler es una excelente manera de filtrar las asignaciones administradas y enfocarse en las que necesites.

Auditor de proyectos

El Auditor de Proyectos, introducido como un paquete en Unity 6.1, es una herramienta de análisis poderosa para proyectos de Unity, diseñada para ayudar a los desarrolladores a optimizar el rendimiento, mantener las mejores prácticas e identificar problemas y cuellos de botella potenciales en sus proyectos.

El Auditor de Proyectos escanea todo tu proyecto y proporciona informes detallados sobre ineficiencias, como llamadas de scripting pesadas, activos no utilizados, conteos excesivos de entidades, etc.

El Auditor de Proyectos cubre varias áreas diferentes:

Optimización del rendimiento: Identifica problemas que podrían afectar el rendimiento en tiempo de ejecución de tu proyecto, como la generación excesiva de basura, asignaciones innecesarias de objetos o llamadas a funciones costosas.

Revisión de código y activos: Destaca activos no utilizados, patrones de código ineficientes o APIs obsoletas que pueden ser refactorizadas. Esto ayuda a reducir el tamaño de la compilación, mejorar la mantenibilidad general del proyecto y optimizar el uso de memoria.

Diagnósticos y mejores prácticas: Proporciona recomendaciones basadas en las mejores prácticas de Unity y destaca errores o advertencias relacionadas con la configuración de tu proyecto, como referencias faltantes o configuraciones de Player o Calidad subóptimas.

Informes personalizables: Organiza los resultados en categorías, facilitando la priorización de optimizaciones. También puedes crear reglas personalizadas para adaptar el análisis a tu proyecto o necesidades específicas.

💡Sugerencias:

- Ejecuta el Auditor de Proyectos en etapas clave del desarrollo (por ejemplo, antes de hitos, lanzamientos beta, compilaciones finales). Las auditorías regulares ayudan a detectar cuellos de botella en el rendimiento, activos no utilizados o código obsoleto temprano, evitando que los problemas crezcan a medida que tu proyecto se expande.

- Puedes automatizar la ejecución del Auditor de Proyectos como parte de tu configuración de CI o compilación (como se muestra aquí en el manual) y usar los informes para asegurarte de que nadie registre activos o código que agregue nuevos problemas (usando la API detallada aquí).

- Puedes agregar tus propias reglas si hay cosas particulares que quieres asegurarte de capturar en tu juego; por ejemplo, configuraciones de texturas, tamaños o reglas más complicadas. Consulta esta página en el manual para más detalles sobre cómo hacer esto.

Los informes generados por el Auditor de Proyectos están categorizados por severidad (Mayor, Moderado e Información). Concéntrate primero en los problemas más graves, ya que a menudo destacan problemas críticos de rendimiento, como la sobreasignación de memoria o la recolección excesiva de basura. También es probable que estén en rutas de código que se llaman con más frecuencia, como Update, donde cualquier problema de rendimiento que traigan será más obvio para los jugadores.

El Auditor de Proyectos también verifica configuraciones como Configuraciones del jugador y Configuraciones de calidad y hace recomendaciones sobre lo que podrías cambiar. Utiliza esto para asegurarte de que tus objetivos de compilación, resolución, compresión de texto u otras configuraciones del proyecto estén optimizados para tu plataforma prevista.

Recarga de dominio

El Editor de Unity te permite configurar ajustes sobre la entrada en modo de juego; esta página tiene más detalles al respecto, pero a menudo puedes acelerar tu tiempo de iteración en el Editor desactivando la Recarga de Dominio. Sin embargo, esto ya no restablecerá tu estado de scripting cada vez que entres en modo de juego, por lo que debes hacerlo manualmente en tu código.

El área de Código en el Auditor de Proyectos puede analizar los scripts en tu proyecto para ayudarte a encontrar cualquier lugar donde necesites restablecer tus variables de script. Se considera una buena práctica solucionar todos los problemas mostrados en la vista de Recarga de Dominio y luego desactivar la recarga de dominio. Para poblar esta vista con datos, debes habilitar la configuración Usar analizadores de Roslyn en la ventana de Preferencias. Luego puedes revisar la lista de problemas, siguiendo las instrucciones en el manual para solucionarlos. Una vez que todos estén abordados, puedes desactivar la Recarga de Dominio al entrar en modo de juego.

La vista Resumen del Auditor de Proyectos
La vista Resumen del Auditor de Proyectos

Optimización de memoria y GC

Unity utiliza el recolector de basura Boehm-Demers-Weiser para limpiar automáticamente la memoria cuando ya no se necesita para tu aplicación. El GC detiene la ejecución de tu código de programa y solo reanuda la ejecución normal una vez que su trabajo está completo.

Si bien la gestión automática es conveniente, las asignaciones innecesarias o frecuentes pueden provocar problemas de rendimiento porque el recolector de basura tiene que pausar tu juego para limpiar la memoria no utilizada (también conocido como picos de GC). Aquí hay algunas trampas comunes a tener en cuenta:

Cadenas: En C#, las cadenas son tipos de referencia, no tipos de valor. Esto significa que cada nueva cadena se asignará en el montón administrado, incluso si solo se usa temporalmente. Reduce la creación o manipulación innecesaria de cadenas. Evita analizar archivos de datos basados en cadenas como JSON y XML, y almacena datos en ScriptableObjects o formatos como MessagePack o Protobuf en su lugar. Usa la clase StringBuilder si necesitas construir cadenas en tiempo de ejecución.

Llamadas a funciones de Unity: Algunas funciones de la API de Unity crean asignaciones en el montón, particularmente aquellas que devuelven un array de objetos gestionados temporales. Almacena referencias a arrays en lugar de asignarlos en medio de un bucle. Además, aprovecha ciertas funciones que evitan generar basura. Por ejemplo, usa GameObject.CompareTag en lugar de comparar manualmente una cadena con GameObject.tag (ya que devolver una nueva cadena crea basura).

También puedes usar el Project Auditor para listar estas alternativas; esto puede ayudar a asegurar que estás usando las versiones que no asignan donde sea posible.

Boxing: El boxing ocurre cuando un tipo de valor (por ejemplo, int, float, struct) se convierte en un tipo de referencia (por ejemplo, object). Evita pasar una variable de tipo valor en lugar de una variable de tipo referencia. Esto crea un objeto temporal, y la posible basura que viene con ello convierte implícitamente el tipo de valor en un tipo objeto (por ejemplo, int i = 123; object o = i). En su lugar, intenta proporcionar sobrecargas concretas con el tipo de valor que deseas pasar. Los genéricos también se pueden usar para estas sobrecargas.

Corutinas: Aunque yield no produce basura, crear un nuevo objeto WaitForSeconds sí lo hace. Almacena en caché y reutiliza el objeto WaitForSeconds en lugar de crearlo en la línea de yield.

LINQ y expresiones regulares: Ambos generan basura debido al boxing detrás de escena. Evita LINQ y expresiones regulares si el rendimiento es un problema. Escribe bucles for y utiliza listas como alternativa a la creación de nuevos arreglos.

Colecciones genéricas y otros tipos administrados: No declares y pobles una lista o colección en cada fotograma en Update (por ejemplo, una lista de enemigos dentro de un cierto radio del jugador). En su lugar, haz que la lista sea un miembro del MonoBehaviour y inicialízala en Start. Simplemente vacía la colección con Clear cada fotograma antes de usarla.

Recolección de basura de tiempo siempre que sea posible

Si estás seguro de que un congelamiento de recolección de basura no afectará un punto específico en tu juego, puedes activar la recolección de basura con System.GC.Collect. Un ejemplo clásico de esto es cuando el usuario está en un menú o pausa el juego, donde no será notable.

Consulta Entendiendo la gestión automática de memoria para ejemplos de cómo usar esto a tu favor.

Usa el recolector de basura incremental para dividir la carga de trabajo del GC

En lugar de crear una única interrupción larga durante la ejecución de tu programa, la recolección de basura incremental utiliza múltiples interrupciones más cortas que distribuyen la carga de trabajo a lo largo de muchos fotogramas. Si la recolección de basura está causando una tasa de fotogramas irregular, prueba esta opción para ver si reduce el problema de los picos de GC. Usa el analizador de perfiles para verificar su beneficio para tu aplicación.

Ten en cuenta que usar el GC en modo incremental agrega barreras de lectura-escritura a algunas llamadas de C#, lo que conlleva cierta sobrecarga que puede sumar hasta ~1 ms por fotograma de sobrecarga de llamada de scripting. Para un rendimiento óptimo, es ideal no tener asignaciones de GC en los bucles de juego principales para que no necesites el GC incremental para una tasa de fotogramas suave y puedas ocultar el GC.Collect donde un usuario no lo notará, por ejemplo, al abrir el menú o cargar un nuevo nivel. En tales escenarios optimizados, puedes realizar recolecciones de basura completas y no incrementales (usando System.GC.Collect()).

Para aprender más sobre el perfilador de memoria, consulta los siguientes recursos:

Guía y tutorial del perfilador de memoria

Documentación del perfilador de memoria

Mejorar el uso de memoria con el Memory Profiler en Unity

Profiler de memoria: La herramienta para solucionar problemas relacionados con la memoria

Trabajando con el Memory Profiler

llamada recortada
Más consejos para Unity 6

Puedes encontrar muchas más prácticas recomendadas y consejos para desarrolladores y creadores avanzados de Unity en el centro de prácticas recomendadas de Unity. Elige entre más de 30 guías, creadas por expertos de la industria, ingenieros de Unity y artistas técnicos, que te ayudarán a desarrollar de manera eficiente con las herramientas y sistemas de Unity.