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:
This is the memory Unity uses to store all its state, managed and native objects and currently loaded assets and scenes. This is similar to the memory used by Unity Players on any other platform. You can configure the size of this in the Unity WebGL Player settings (But for faster iteration, you can also edit the TOTAL_MEMORY value written to the generated html file). You can use the Unity Profiler to profile and sample the contents of this memory. This memory will be created as a TypedArray of bytes in JavaScript code, and requires the browser to be able to allocate a consecutive block of memory of this size. You want this space to be as small as possible (so that the browser can allocate it even if memory is fragmented), but large enough to fit all the data required to play any scene of your content.
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)).
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.
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.
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.
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";
}
2018–08–23 Page amended with no editorial review