Bueno, creo que escuché el nombre V8 un millón de veces. La primera vez que surgió fue en 2008, cuando un ingeniero de mi equipo me explicó por qué el rendimiento de algún código sería bueno. Dijo: "¡V8 se encargará de eso!" - Asenti. Aunque no sabía de qué estaba hablando, todavía quería parecer actualizado con las palabras técnicas de front-end que nos inundaban en estos días. Luego, cuando volví a mi computadora, lo busqué en Google y pensé: genial, nuevo motor de JavaScript que usa Chrome, genial, supongo.
Esta primera línea en Wikipedia es lo que la mayoría de nosotros sabemos sobre V8 y sobre muchas otras cosas. Aquí intentaré proporcionar una explicación sencilla de lo que realmente hace V8. En cuanto a las otras cosas, la próxima vez, solo lee el primer párrafo completo en Wikipedia, qué diablos, solo se vive una vez, sumérgete en el segundo.
Así que sí, "V8 es el motor WebAssembly y JavaScript de alto rendimiento de código abierto de Google, escrito en C++" ( documentación de V8 ), pero ¿qué significa esto realmente? Bueno, en realidad significa que V8 es un programa C++, que recibe código JavaScript, lo compila y lo ejecuta.
V8 es un motor de ejecución de un solo subproceso. Está diseñado para ejecutar exactamente un subproceso por contexto de ejecución de JavaScript. En realidad, puede ejecutar dos motores V8 en el mismo proceso, por ejemplo, trabajadores web, pero no compartirán ninguna variable o contexto como hilos reales. Esto no significa que V8 se esté ejecutando en un solo subproceso, sino que proporciona un flujo de JavaScript de un solo subproceso.
En el tiempo de ejecución, V8 administra principalmente la asignación de memoria en montón y la pila de llamadas de un solo subproceso. La pila de llamadas es principalmente una lista de funciones para ejecutar, por orden de llamada. Cada función que llama a otra función se insertará una tras otra directamente, y las devoluciones de llamada se enviarán al final. En realidad, esta es la razón por la que llamar a una función con setTimeout de cero milisegundos la envía al final de la línea actual y no la llama de inmediato (0 milisegundos).
V8 obtiene su velocidad de la compilación de JavaScript justo a tiempo (JIT) en código de máquina nativo, justo antes de ejecutarlo. En primer lugar, el código es compilado por un compilador de referencia, que genera rápidamente un código de máquina no optimizado. En tiempo de ejecución, el código compilado se analiza y se puede volver a compilar para un rendimiento óptimo. Ignition proporciona el primero mientras que TruboFan & Crankshaft el segundo.
El código de máquina del resultado de la compilación JIT puede ocupar una gran cantidad de memoria, mientras que podría ejecutarse una vez. Esto se soluciona con Ignition, que ejecuta código con menos sobrecarga de memoria.
El proyecto TurboFan comenzó en 2013 para mejorar la debilidad de Crankshaft, que no está optimizado para alguna parte de la funcionalidad de JavaScript, por ejemplo, el manejo de errores. Fue diseñado para optimizar tanto las funciones existentes como las futuras planificadas en ese momento.
Blog de desarrollo de V8: https://v8.dev/blog/ignition-interpreter
Lograr un gran rendimiento también es clave en el navegador, y esta es la tarea para la que se utiliza Liftoff: generar código de máquina. Al no utilizar la compleja compilación de varios niveles, Liftoff es un generador de código más simple, que genera código para cada código de operación (una parte única del código de máquina, que especifica una operación a realizar) a la vez. Liftoff genera código mucho más rápido que TurboFan (~10x), que obviamente tiene menos rendimiento (~50%). Para obtener más información, consulte el Blog de desarrollo de V8 .
Corriendo sobre el montón de memoria, en busca de asignaciones de memoria desconectadas está el Orinoco. Implementar un recolector de basura generacional, moviendo objetos dentro de la generación joven, de la generación joven a la vieja y dentro de la generación vieja. Estos movimientos dejan huecos y Orinoco realiza tanto la evacuación como la compactación para liberar espacio para más objetos.
Otra optimización realizada por Orinoco es la forma en que busca en el montón para encontrar todos los punteros que contienen la ubicación anterior de los objetos movidos y actualizarlos con la nueva ubicación. Esto se hace usando una estructura de datos llamada conjunto recordado.
Además de estos, se agrega la asignación de negro , lo que básicamente significa que el proceso de recolección de basura marca automáticamente los objetos vivos en negro para acelerar el proceso de marcado iterativo.
JavaScript no pretende ser el lenguaje del lado del servidor más optimizado para una gran escala y rendimiento. Sin embargo, desde la introducción de V8 y las mejoras arquitectónicas anteriores, el conjunto de herramientas que un desarrollador web puede usar se transformó por completo, lo que permitió grandes mejoras y nuevas funciones.
Espero que esta prueba rápida del V8 lo haya ayudado a obtener una comprensión básica simplificada del motor V8 que ejecuta el código JavaScript en el cliente y el servidor.