El uso de la memoria es fundamental en el desarrollo de juegos para Android. Cuando desarrolles juegos con Unreal Engine, debes analizar y hacer un seguimiento continuo del estado de la memoria para satisfacer estas restricciones, evitar pérdidas de memoria y asignaciones excesivas.
Ahorro de memoria a través de la reducción de la permutación del sombreador
Si quitas las opciones que no se usan en Lighting o Mobile Shader Permutation
Reduction, puedes minimizar la cantidad de permutaciones del sombreador. Esto reduce significativamente el tamaño del paquete de la app, disminuye la cantidad de objetos de estado de canalización (PSO) y evita la creación de objetivos de renderización o texturas ficticias que no se usan, lo que reduce la memoria de tiempo de ejecución y mejora el rendimiento.
Para obtener más información, consulta la sección Misc Lighting and Shader Permutation Reduction Settings for Mobile en los Lineamientos de rendimiento para dispositivos móviles.
Optimización de la carga de recursos
Cuando se cargan recursos con referencias directas, el contenido conectado que ni siquiera se usa en el juego se carga en la memoria de forma simultánea, lo que provoca un consumo de memoria innecesario. En particular, cuando la herencia se usa de forma incorrecta en los planos, se asignan CDO (objetos predeterminados de clase) innecesarios de los elementos superiores, lo que desperdicia una cantidad significativa de memoria. En esos casos, aplica las siguientes técnicas para optimizar el uso de la memoria.
- Definición de código C++ y separación de datos: Define las funcionalidades principales
con
UCLASS(Abstract)en el código C++, separándolas de los datos reales. - Minimiza la herencia: Realiza la configuración de datos y la carga de recursos solo en los planos de nodos hoja.
- Usa referencias indirectas: Aplica referencias de propiedades indirectas con
TSoftObjectPtrpara evitar referencias directas y carga recursos de forma asíncrona solo cuando sea necesario en el tiempo de ejecución. - Precauciones: Cuando uses la carga de recursos asíncrona, asegúrate de que se realicen verificaciones de validez
(
IsValid) durante la devolución de llamada de finalización de la carga para evitar punteros colgantes o fallas.
Para obtener más información, consulta Referencia de recursos y Creación de juegos para dispositivos móviles con UE5.
Punteros inteligentes y ajuste de la recolección de elementos no utilizados (GC)
El uso de punteros inteligentes (como TSharedPtr y TWeakPtr) durante el desarrollo de C++ evita punteros colgantes y pérdidas de memoria. Además, el uso de TWeakPtr evita la creación de referencias directas a objetos, por lo que el recolector de elementos no utilizados no aumenta los recuentos de referencias cuando recopila objetos. Esto evita la supervivencia innecesaria de objetos y reduce la complejidad del gráfico de referencias que GC necesita atravesar, lo que reduce significativamente la sobrecarga de GC. La recolección de elementos no utilizados se puede administrar de manera eficaz en entornos móviles activando ForceGarbageCollection durante las transiciones de nivel o los períodos de inactividad, como cuando no hay interacción del usuario. Además, se puede activar cuando el juego está en un estado perceptible o en segundo plano (por ejemplo, devoluciones de llamada onStop), lo que garantiza que la recolección de elementos no utilizados se realice sin afectar la experiencia de juego activa.
Para obtener más información, consulta Recolección de elementos no utilizados y puntero inteligente.
Optimización con compresión de tablas de reubicación
La compresión de tablas de reubicación es un método de optimización que comprime el tamaño de la tabla de reubicación en archivos binarios ELF para reducir el tamaño binario de Android. Cuando Android minSDKVersion es 23 o superior, se admite la compresión de tablas de reubicación de APS. Cuando minSDKVersion es 28 o superior, también se admite la compresión de tablas de reubicación de RELR, lo que reduce significativamente el tamaño del archivo .so. Esto no solo disminuye el tamaño de descarga, sino que también reduce el espacio en memoria de .so mmap en el tiempo de ejecución, lo que mitiga la presión general de la memoria física.
AndroidToolChain.cs
if (MinSDKVersion >= 28)
{
Result += " -Wl,--pack-dyn-relocs=android+relr,--use-android-relr-tags";
}
else if (MinSDKVersion >= 23)
{
Result += " -Wl,--pack-dyn-relocs=android";
}
Para aplicar esta optimización, verifica que Enable compression of relocation tables en la configuración del proyecto o que la variable bEnableAdvancedBinaryCompression esté habilitada.
Para verificar si la compresión RELR se aplica correctamente al archivo binario, usa la herramienta llvm-readelf del NDK de Android.
llvm-readelf -d libUnreal.so | grep RELR
En la práctica, la creación de la plantilla ThirdPerson de Unreal Engine y la medición con dumpsys meminfo confirman una reducción en el uso de PSS y RSS para .so mmap.
| Categoría | PSS total | Privado no sincronizado | Privado limpio | Intercambio no sincronizado | RSS total |
|---|---|---|---|---|---|
| .so mmap antes de la compresión | 170,210 | 24,360 | 141,564 | 0 | 242,204 |
| .so mmap después de la compresión | 138,031 | 24,748 | 108,976 | 0 | 210,140 |
Compresión de texturas
Usa la compresión de texturas adecuada para reducir el espacio en memoria de los recursos gráficos generales. El uso de la compresión de textura escalable y adaptable (ASTC), el estándar para dispositivos móviles, proporciona una calidad visual superior en comparación con ETC2 con el mismo tamaño, o bien logra proporciones de compresión más altas con un menor consumo de memoria con el mismo objetivo de calidad visual.
Optimización de la transmisión de texturas
En entornos móviles, el uso directo del tamaño predeterminado del grupo de transmisión de texturas de Unreal Engine puede asignar previamente un grupo de memoria excesivamente grande en relación con las especificaciones del dispositivo. Por lo tanto, es ideal definir perfiles de dispositivos móviles y seleccionar un tamaño de grupo de transmisión de texturas adecuado según los límites de memoria del dispositivo. Además, usa la función Statistic del editor para verificar las estadísticas de texturas y, luego, identificar las texturas que consumen mucha memoria y que ocupan resoluciones extremas en el tiempo de ejecución. Combina esto con la función Required Texture Resolution para aplicar límites o reducir las resoluciones máximas en texturas exigentes, lo que mantiene el uso de recursos controlado dentro del búfer de memoria de texturas asignado.