Consideraciones de rendimiento WebGL
WebGL: Interactuando con scripting del navegador

Consideraciones de Memoria cuando tenga como objetivo WebGL

La memoria en Unity WebGL puede ser un factor limitante restringiendo la complejidad del contenido que usted puede ejecutar, por lo que queremos proporcionarle una explicación acerca de cómo la memoria es utilizada en WebGL.

Su contenido WebGL va a ejecutarse dentro de un navegador, por lo que cualquier memoria tiene que ser asignada por el navegador dentro del espacio de memoria del navegador. La cantidad de memoria disponible puede variar mucho dependiendo en el navegador, OS y dispositivo utilizado. Los factores determinantes incluyen si el navegador es un proceso de 32 o 64 bit, si el navegador utiliza procesos separados para cada pestaña o si su contenido comparte un espacio de memoria con todas las otras pestañas abiertas, y qué tanta memoria el motor JavaScript del navegador requiere para parse su código.

Hay múltiples áreas dónde el contenido de Unity WebGL va a requerir que el navegador asigne cantidades significantes de memoria:

Unity Heap

Esta es la memoria que Unity utiliza para almacenar su estado, objetos managed y nativos y assets actualmente cargadas y escenas. Esta es similar a la memoria utilizada por los reproductores de Unity en cualquier otra plataforma. Usted puede configurar el tamaño de esto en los ajustes del Unity WebGL player (pero para una iteración más rápida, usted puede editar el valor TOTAL_MEMORY escrito al archivo html generado). Usted puede utilizar el Unity Profiler para perfilar y muestrar los contenidos de esta memoria. Esta memoria será creada como un TypedArray de bytes en código JavaScript, y requiere que el navegador sea capaz de asignar un bloque de memoria consecutivo de este tamaño. Usted querrá que este espacio sea tan pequeño como posible (para que el navegador sea capaz de asignarla equitativamente si la memoria es fragmentad), pero lo suficientemente grande para que encaje todos los datos requeridos para reproducir cualquier escena de su contenido.

Datos de Asset

Cuando usted cree una construcción de Unity WebGL, Unity va a escribir un archivo .data conteniendo todas las escenas y assets necesitados para su contenido. Debido a que WebGL no tiene un sistema de archivos verdaderos, este archivo será descargado antes de que su contenido inicie, y los datos sin comprimir serán mantenidos en un bloque consecutivo de memoria del navegador para todo el tiempo que su contenido se ejecute. Entonces, para mantener ambos tiempos de descargar y el uso de memoria bajo, usted debería intentar mantener estos datos tan pequeños como sean posibles. Ver la página de documentación acerca de reducir el tamaño de archivos para información acerca de cómo optimizar el tamaño de la construcción para sus assets.

Otra cosa que usted puede hacer para reducir el tiempo de carga y la cantidad de memoria utilizada para los assets es empaquetar sus datos de asset en AssetBundles. Al hacer esto, usted obtiene un control completo de cuando sus assets necesitan ser descargados, y usted puede descargarlos nuevamente cuando usted no los necesite, lo cual liberará cualquier memoria utilizada por estos. Tenga en cuenta que los AssetBundles serán cargados directamente a su Unity heap y no va a resultar en asignaciones adicionales por el navegador (al menos de que usted utilice Asset Bundle Caching utilizando WWW.LoadFromCacheOrDownload, el cual utiliza un sistema de archivo virtualmente mapeado de memoria, respaldado por el navegador IndexedDB (BD indexada)).

Memoria necesita para parse el código

Otro problema relacionada a memoria es la memoria requerida por el motor JavaScript del navegador. Unity va a emitir una gran cantidad de archivo de millones de lineas de código JavaScript generado, el cual es un orden de magnitud más grande que los usos comunes de código JavaScript en los navegadores. Algunos motores de JavaScript puede asignar algunas estructuras grandes de datos para parse y optimizar ese código, el cual resulta en picos de memoria de hasta varios Gigabytes de memoria cuando carguen contenido en algunos casos. Nosotros esperamos que haya tecnologías en el futuro como WebAssembly que eventualmente eliminen este problema, pero hasta ese entonces, el mejor consejo que podemos dar es que mantenga el tamaño del código emitido bajo. Ver los comentarios del tamaño de distribución aquí para más información acerca de cómo hacer esto.

Trabajando con problemas de memoria

Cuando usted vea un error relacionado a memoria en la construcción de WebGL, es importante entender si es el navegador que está fallando asignando memoria o si es el tiempo de ejecución de Unity WebGL el que falla cuando asigna un bloque libre de memoria dentro del bloque pre-asignado del Unity heap. Si el navegador falla asignando memoria, entonces puede ayudar intentar reducir el tamaño utilizado por uno más áreas de memoria de arriba (por ejemplo al reducir el tamaño del Unity heap). Por otro lado, si es el tiempo de ejecución de Unity el que falla en asignar un bloque dentro del Unity heap, usted puede intentar aumentar el tamaño de este más bien.

Unity va a intentar de interpretar los mensajes de error para decir cuál de los dos es (y proporcionar sugerencias acerca de qué hacer). Debido a que diferentes navegadores pueden reportar diferentes mensajes, esto no es siempre fácil, y puede que no se interprete todos estos. Cuando usted ve un error genérico “Out of memory” del navegador, es probable que sea un problema del navegador que se quede sin memoria (dónde usted podría querer usar un Unity heap más pequeño). También, usted a veces ver navegadores que simplemente fallan cuando carguen contenido de Unity sin mostrar mensajes de error parseables a humano. Esto puede tener muchas razones, pero es frecuentemente causado por motores de JavaScript requiriendo mucha memoria para parse y optimizar el código generado.

Consideraciones del Garbage Collection (Recogedor de basura)

Cuando usted asigne objetos managed a Unity, estos necesitan ser recolectados por la basura cuando no estén en uso. Ver nuestra documentación acerca del manejo de memoria automático para más información. En WebGL, esto es lo mismo. Memoria Managed, recolectada por basura es asignada dentro del Unity heap.

Una distinción en WebGL, sin embargo, concierne a los puntos en el tiempo dónde el recolector de basura (garbage collection -GC-) toma lugar. Para realizar la recolección de basura, el GC normalmente necesitaría pausar todos los hilos ejecutándose e inspeccionaría sus stacks y registros por referencias de objetos cargados. Esto no es actualmente posible en JavaScript. Por esta razón, el GC va a solamente ejecutarse en WebGL en situaciones dónde el stack es conocido por estar vacío (el cual es una vez después de cada frame). Este no es un problema para la mayoría de contenido que trata con memoria managed de manera conservativa y tiene pocas asignaciones GC dentro de cada frame (usted puede depurar esto utilizando el profiler de Unity).

Sin embargo, si usted tiene código como el siguiente:

string hugeString = "";

for (int i = 0; i < 100000; i++)
{
    hugeString += "foo";
}

, luego este código fallaría corriendo en WebGL, ya que no tendría chance de ejecutar las GC entre iteraciones del bucle, para librar memoria utilizada por todos los objetos string intermediarios - lo cual eventualmente causaría que se quedará sin memoria en el Unity heap.

Consideraciones de rendimiento WebGL
WebGL: Interactuando con scripting del navegador