Sistema
LomentGC
Cuando un programa Loment libera memoria, no le pasa todo el trabajo a un recolector. Cada lugar que asigna queda asignado, en tiempo de compilación, a una de cuatro estrategias — y cuánto se deja al recolector del runtime es un número escrito en el binario, y no una afirmación en un documento.
La escala
De la más fuerte a la más débil: el compilador toma el nivel más fuerte que puede demostrar. Demostrar más, pagar menos. El precio de cada nivel se escribe a su lado en lugar de dejarlo en una nota al pie.
L0 — estático
La asignación es de tamaño literal, y el puntero solo se pasa entero como primer argumento de una carga, un almacenamiento o una operación atómica. Nunca llega al montículo, así que no hay nada que recuperar. El precio: un marco de pila más grande.
L1 — último uso
La misma forma, declarada en el nivel superior del cuerpo de una función, así que el
último uso es contable. El compilador inserta un free antes del
primer retorno posterior a él. El precio: en una vía de retorno
temprano el punto de inserción puede pasarse por alto, y esa vía fuga una vez. Una
fuga, no un bug.
L2 — épocas de bloque
Dentro del cuerpo de un bucle, cada asignación es un local que nunca sale del cuerpo. El final del cuerpo devuelve toda la región de una vez, rebobinando el frente del asignador — sin lista, sin barrido. La época se infiere de la estructura de bloque y del escape, no se escribe a mano. El precio: si una asignación del cuerpo escapa, todo el bloque debe permanecer.
L3 — runtime
Todo lo que el compilador no pudo demostrar. El coste pleno del recolector.
Tres niveles
Un programa selecciona hasta qué punto de la escala está dispuesto a bajar, con una línea en el archivo del que parte.
choose gc_manual
El valor por defecto. Nada se recupera automáticamente; el programa gestiona su propia memoria. No escribir ninguna línea da esto — el valor por defecto es el comportamiento que existía antes de que el ajuste existiera, que es la regla que sigue cada ajuste.
choose gc_auto
Un recolector en tiempo de ejecución recupera: marcado y barrido con raíces precisas, disparado por el número de bytes asignados.
choose gc_auto_alpha
Los cuatro peldaños están activos, así que el recolector solo ve lo que los peldaños de tiempo de compilación no pudieron demostrar — y es adaptativo: el umbral sigue al conjunto vivo, con un disparador por espacio, así que el techo no es una fracción fija del arena.
Un límite que se enuncia en lugar de descubrirse. Bajo
gc_auto el disparador es de 32 KiB fijos mientras el arena es de 64 KiB, así
que un programa cuyo conjunto vivo supera aproximadamente 32 KB se queda sin
memoria igualmente. Cerrar esa brecha es para lo que sirven el recolector adaptativo, y
el generacional bajo gc_auto_alpha.
Dentro de L3
El nivel de runtime tampoco es un único algoritmo. Creció en tres pasos, cada uno de los cuales tuvo que superar al anterior en un programa que el proyecto podía medir.
Marcado y barrido
Las raíces son precisas — la tabla de raíces guarda direcciones de ranura —
mientras que el interior de un bloque se trata de forma conservadora, porque
alloc no está tipado y nada registra qué contiene un bloque.
Disparo adaptativo
Un umbral fijo tiene que adivinar cuánto crecerá el conjunto vivo. Uno adaptativo lo lee: recolecta cuando el conjunto vivo se ha duplicado, o cuando escasea el espacio.
Generacional
Dos generaciones, cortadas por dirección en lugar de por edad del objeto — un recolector que no mueve promueve al final de cada recolección menor avanzando una frontera. Una tabla de tarjetas y una barrera de escritura capturan los punteros de viejo a joven. Lo que ahorra es la pasada de marcado y propagación, que entonces cubre solo la generación joven.
Por qué queda en el binario
Cada unidad exporta un resumen legible por máquina — un objeto de forma — que
lleva gc_ladder: cuántos sitios de asignación tomó cada nivel, más el total.
Los cuatro recuentos deben sumar el total, y dos programas independientes
comprueban esa aritmética sin leer una línea de código fuente. Así, «cómo se
gestiona la memoria de este programa» es un número en la salida de compilación en lugar
de una afirmación en un documento.
Lo que se afirma, y lo que no. La escala está implementada dos veces — el compilador de referencia y el autoalojado — y los dos deben coincidir byte por byte. Las mediciones detrás de los peldaños vienen de los propios criterios del proyecto, que son programas pequeños; el recolector no se ha ejecutado contra una carga de trabajo real, y eso vale la pena saberlo antes de leer nada de esto como una afirmación de rendimiento.