Aprenda a ahorrar memoria mejorando la forma en que utiliza AssetBundles

Ya sea que su aplicación transmita activos desde una red de distribución de contenido (CDN) o los empaquete todos en un gran binario, probablemente haya oído hablar de AssetBundles. Un AssetBundle es un archivo que contiene uno o más activos serializados (texturas, mallas, clips de audio, sombreadores, etc.) y se puede cargar en tiempo de ejecución.
Los AssetBundles se pueden utilizar directamente o a través de sistemas como Unity Addressable Asset System (también conocido como Addressables). El sistema Addressables es un paquete que proporciona una forma más accesible y con soporte de administrar activos dentro de sus proyectos. Es una abstracción sobre AssetBundles. Si bien Addressables minimiza las interacciones directas que los desarrolladores tienen con AssetBundles, es útil comprender cómo el uso de AssetBundles puede afectar el uso de la memoria. Para obtener una descripción general del sistema Addressables, consulte esta publicación de blog y esta sesión de Unite Copenhagen 2019.
Los desarrolladores que trabajan en proyectos nuevos deberían considerar usar Addressables en lugar de trabajar directamente con AssetBundles. Si está trabajando en un proyecto con un enfoque de AssetBundles ya establecido, la información aquí sobre cómo los AssetBundles afectan la memoria en tiempo de ejecución lo ayudará a obtener los mejores resultados posibles.
Cuando Unity descarga un AssetBundle LZMA utilizando la clase WWW (que ahora está obsoleta) o UnityWebRequestAssetBundle (UWR), Unity optimiza la obtención, la recompresión y el control de versiones de AssetBundles utilizando dos cachés: el caché de memoria y el caché de disco.
Los AssetBundles cargados en la memoria caché consumen una gran cantidad de memoria. A menos que desees específicamente acceder frecuente y rápidamente al contenido de un AssetBundle, la memoria caché probablemente no valga la pena. En su lugar, utilice la caché del disco.
Si proporciona una versión o un argumento hash a la API UnityWebRequestAssetBundle , Unity almacena sus datos AssetBundle en la memoria caché del disco. Si no proporciona estos argumentos, Unity utiliza la memoria caché. Tenga en cuenta que Addressables utiliza el caché de disco de forma predeterminada. Este comportamiento se puede controlar a través del campo UseAssetBundleCache.
AssetBundle.LoadFromFile() y AssetBundle.LoadFromFileAsync() siempre utilizan la memoria caché para LZMA AssetBundles. Por lo tanto, recomendamos utilizar la API UnityWebRequestAssetBundle en su lugar. Si no es posible utilizar la API UnityWebRequestAssetBundle, puede utilizar AssetBundle.RecompressAssetBundleAsync() para reescribir un LZMA AssetBundle en el disco.
Las pruebas internas muestran que hay al menos un orden de magnitud de diferencia en RAM entre el uso del caché de disco y el uso del caché de memoria. Debe sopesar la compensación entre el costo de la memoria y los requisitos de espacio en disco adicionales y el tiempo de creación de instancias de activos para su aplicación.
Para determinar qué efecto puede tener la memoria caché de AssetBundle en el uso de memoria de su aplicación, utilice un generador de perfiles nativo (nuestra herramienta preferida es el Instrumento de asignaciones de Xcode) para examinar las asignaciones de la clase ArchiveStorageConverter. Si esta clase usa más de 10 MB de RAM, probablemente esté usando la memoria caché.

Al crear AssetBundles para proyectos grandes, no asuma que Unity, de manera predeterminada, minimizará la cantidad de información duplicada entre ellos. Para identificar instancias de datos duplicados en los AssetBundles generados, puede utilizar el práctico AssetBundle Analyzer, escrito en Python por uno de nuestros colegas del grupo de Consultoría y Desarrollo. Utilizada a través de la línea de comandos, la herramienta extrae información de los AssetBundles generados, que luego se almacena en una base de datos SQLite que presenta varias vistas útiles. Luego puede consultar la base de datos utilizando herramientas como DB Browser para SQLite. Esta herramienta puede ayudarle a encontrar y resolver cualquier ineficiencia en su proceso de compilación, ya sea que haya creado paquetes manualmente o mediante direccionables.

Alternativamente, consulte la herramienta AssetBundle Browser, que puede descargar e integrar en su proyecto de inmediato. Tenga en cuenta que esta herramienta proporciona una funcionalidad similar a Addressables, por lo que si está utilizando Addressables, esta herramienta no es relevante.
La herramienta AssetBundle Browser le permite ver y editar la configuración de AssetBundles en un proyecto Unity determinado y proporciona funcionalidad de compilación. También proporciona algunas características interesantes, como informar a los usuarios sobre activos duplicados que se extraen debido a dependencias, como texturas.

Al decidir cómo organizar sus activos en AssetBundles, debe tener cuidado con las dependencias. Independientemente de su topología de AssetBundle, Unity hace una distinción entre los activos que residen dentro del binario de la aplicación (en o dentro de una carpeta de recursos) y aquellos que necesita cargar desde AssetBundles. Puedes pensar en estos dos tipos de activos como si vivieran en mundos diferentes. Es imposible crear un AssetBundle que tenga una referencia fija a la instancia de un Asset dentro del mundo de la carpeta Resources. Para hacer referencia a esos activos, Unity hace una copia de los activos que utiliza en el mundo AssetBundle.


Tomemos como ejemplo el logotipo de un juego. El logotipo puede mostrarse en la interfaz de usuario de una escena de carga mientras se inicia el juego. Dado que esta pantalla de carga debe mostrarse antes de que los activos remotos se transmitan al disco, es posible que incluya el activo del logotipo en la compilación para que pueda usarse de inmediato.
Este mismo logotipo también se utiliza en un panel de opciones en la interfaz de usuario, donde los usuarios pueden seleccionar su idioma, preferencias de sonido y otras configuraciones. Si este panel de interfaz de usuario se carga desde un AssetBundle, entonces ese AssetBundle creará su propia copia del logotipo Asset.
Si se cargan al mismo tiempo la pantalla de carga y el panel de opciones, se cargarán ambas copias del logotipo Asset, lo que supone una duplicación que consume memoria.
La solución a este problema es romper el vínculo duro entre una o ambas pantallas. Si el logotipo se encuentra en un AssetBundle, entonces es necesario que se produzca cierta cantidad de transmisión antes de poder obtener una referencia al Asset. Si el logotipo se encuentra en el binario (dentro de una carpeta de Recursos, por ejemplo), entonces el panel de UI deberá tener una referencia débil al recurso del logotipo y cargarse a través de una API como Resources.Load.

Los scripts de usuario deberán usar la cadena para cargar la imagen en tiempo de ejecución y asignarla al componente adecuado. Un término medio feliz puede ser incluir el AssetBundle que contiene el logotipo Asset dentro del directorio StreamingAssetsde la aplicación. Aún cargarás el activo desde AssetBundle, pero como estás alojando el paquete localmente, no pagarás el costo en tiempo requerido para descargar el contenido.
No es intuitivo usar cadenas, rutas o GUID para hacer referencia a activos, pero es posible que desee crear inspectores personalizados que habiliten la funcionalidad de referencia de arrastrar y soltar predeterminada de Unity en sus campos con referencias débiles. Y no olvide utilizar el paquete MemoryProfiler de Unity para identificar activos que están duplicados en la memoria. Tenga en cuenta que el sistema Addressables tiene su propio mecanismo para verificar duplicados en las dependencias (para obtener más información, consulte la documentación).
Si bien el sistema Addressables proporciona una abstracción sobre AssetBundles, saber cómo funcionan las cosas bajo el capó puede ayudarle a evitar problemas de rendimiento costosos como los que se describen en este artículo.
Si actualmente utiliza Addressables, nos gustaría conocer su opinión a través de esta breve encuesta.
Estamos planeando una hoja de ruta para futuras entradas de esta serie. ¿Hay algún área en la que le gustaría que nos centráramos? ¡Deja un comentario para hacérnoslo saber!
