¿Por qué las CPU modernas no ofrecen recolección de basura asistida por hardware y asignación de memoria?

En el núcleo de una arquitectura de CPU hay un conjunto de instrucciones que admiten la programación de “propósito general”. El conjunto de instrucciones es bastante universal, ya que se puede usar para implementar cualquier programa (mi advertencia es principalmente sobre la capacidad de una CPU para comunicarse con otras CPU).

Más allá de eso, se agregan instrucciones y características arquitectónicas donde son lo suficientemente baratas y brindan suficientes beneficios para que valgan la pena. Los costos y beneficios dependen del contexto: considere agregar un punto flotante de 64 bits a un ARM M0 en comparación con agregar una instrucción para admitir AES a un Intel Xeon.

Históricamente, la asignación de memoria de soporte se ha trasladado al hardware del procesador. Por ejemplo, la gestión de memoria basada en tablas de páginas proporcionada en procesadores de propósito general se desarrolló (entre otras cosas) para resolver el problema de la fragmentación de la memoria; proporciona una forma de tomar un conjunto de páginas con direcciones (físicas) no contiguas y presentarlas a un programa como un conjunto de páginas con direcciones contiguas (virtuales). Tenga en cuenta que hay muy poco (tal vez una instrucción de “sonda”) en el conjunto de instrucciones que lo respalde. El mecanismo de paginación originalmente dependía de las tablas de páginas en la memoria con un caché (TLB) para contener las entradas de tablas de páginas utilizadas recientemente, sin embargo, en la arquitectura MIPS, el TLB fue promovido a ser arquitectónico y administrado por software.

¿Qué pasa con la recolección de basura y la administración de memoria correspondiente, más allá del soporte ofrecido por la administración de memoria basada en páginas? Se ha probado, por ejemplo, en la máquina LISP, pero a medida que la tecnología evoluciona, también cambian varios aspectos del costo-beneficio. Por ejemplo, las técnicas de recolección de basura cambian y los mecanismos estrechamente vinculados al hardware tienden a ser inmutables y obsoletos. [Para comparar, mire cómo el “hardware de Java” ha pasado de moda]. Hay casos en que las máquinas modernas admiten la recolección de basura y la administración de memoria mejor que las máquinas más antiguas. Por ejemplo, el cambio a 64 bits proporciona suficientes bits de puntero que algunos pueden ser “robados” para admitir la recolección de basura y la administración de memoria. (ARM-64 proporciona explícitamente para hacer esto). Apple ha explotado esto (ciertamente para el recuento de referencias en lugar del GC clásico) para reducir el número de referencias de memoria realizadas. Mike Ash dice: (ver viernes Q&A 2013-09-27: ARM64 y usted)

  • “En resumen, las mejoras en el tiempo de ejecución de Apple hacen que la asignación de objetos en modo de 64 bits cueste solo el 40-50% de lo que hace en modo de 32 bits. Si su aplicación crea y destruye muchos objetos, eso es un gran acuerdo.”

¿Se podría hacer más? Probablemente. Sin embargo, hacerlo y explotar cualquier mecanismo requeriría trabajar en muchos niveles de abstracción: diseño del procesador, arquitectura del procesador, herramientas básicas, sistema operativo y sistemas de lenguaje. No hay muchas compañías que se integren lo suficientemente verticalmente como para cubrir estas áreas.

¿Por qué querrías algo así?

Lo primero es lo primero: no estamos evolucionando hacia un conjunto de instrucciones cada vez más complejo. Lo hicimos una vez, sí, pero no volveremos a cometer el mismo error (te estoy mirando, Intel). La mentalidad de hoy está más orientada hacia el hardware RISC que el hardware CISC. Incluso los procesadores Intel a veces reducen CISC a RISC, aunque no tengo idea de qué procesadores hacen esto.

Además, las cosas que dijo, como la criptografía AES (nunca he visto tales instrucciones en ningún dispositivo (bueno, excepto en el conjunto de instrucciones SSE4, pero de todos modos)), instrucciones de puntero (que se utilizan para todo lo que no concierne a los registros: memoria, dispositivos IO, etc.) y memoria virtual (para ejecutar un programa más de una vez), son cosas que son extremadamente importantes e incluidas desde 1970, o que no se incluyen en absoluto, Y todas se ejecutan en registros.

Pero la memoria dinámica?

Con todo malloc -call, el programa:

  • Va a la memoria
  • bloquea la memoria
  • comprueba si todavía hay algún lugar para localizar
  • expande el montón si no hay espacio disponible
  • le pide al kernel más espacio si necesita aún más.
  • localiza la memoria
  • establece el encabezado de la memoria
  • desbloquea el montón
  • devuelve un puntero a la memoria

De todos estos pasos, solo uno de ellos (devolver el puntero) se puede hacer sin acceder a la memoria principal.

La memoria principal es lenta. Extremadamente lento La memoria en sí funciona a unos 200Mhz, y las búsquedas cuestan varios ciclos de memoria, y mucho menos los ciclos de la CPU.
Cuando tuvimos que simular ciclos para medir la velocidad de un programa (usando Valgrind), cada instrucción de memoria equivalía a 153 instrucciones normales. Ni siquiera una exageración.

¿Y pide compilar el proceso en una sola instrucción? No simplemente no. No hay ganancia de velocidad cuando hacemos eso. Peor aún: el malloc sería ininterrumpido y su computadora comenzaría a retrasarse horriblemente.

Y ni siquiera he comenzado la queja sobre la recolección de basura. ¿Cómo sabría el procesador qué memoria desasignar? Incluso la desasignación en sí misma es un proceso complejo y difícil.

Y la recolección de basura se mete con los punteros. No, gracias.

Ellas hacen.

El TLB es una asignación de memoria asistida por hardware.

Azul ofrece CPU con soporte de hardware para barreras de lectura GC. https://www.azul.com/