Consideraciones de rendimiento WebGL
WebGL: Interacting with browser scripting

Memory in 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.

Asset Data

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)).

Memory needed to parse the code

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.

Dealing with memory issues

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.

Asignación grande de encabezado HTTP

Su servidor puede emitir el encabezado http Large-Allocation (asignación grande) para su contenido. Esto le dice a los navegadores compatibles (actualmente solo Firefox) acerca de sus necesidades de memoria, lo que les permite generar un nuevo proceso con un espacio de memoria no fragmentado, o realizar otras tareas domésticas para asegurarse de que la asignación grande sea exitosa. Esto puede resolver problemas donde el navegador se queda sin memoria cuando intenta asignar el montón de Unity, especialmente en los navegadores de 32 bits.

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).

However, the following code would fail running on WebGL, becuase it would not get a chance to run the GC between iterations of the loop, to free up memory used by all the intermediate string objects - which would eventually cause it to run out of memory in the Unity heap.

string hugeString = "";

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

Lecturas adicionales


2018–08–23 Page amended with no editorial review

Consideraciones de rendimiento WebGL
WebGL: Interacting with browser scripting