ArenaAllocators y ArrayLists en Zig: por qué la memoria no se libera como cabría esperar

Fuentes: ArenaAllocators don't play nicely with ArrayLists

En Zig, un ArenaAllocator solo devuelve memoria al «arena» cuando se cumplen dos condiciones: que la liberación afecte a la última asignación y que esa asignación proceda del nodo activo del arena. Si se libera el último bloque (por ejemplo, una variable b asignada después de a), esa condición se cumple y b sí vuelve al arena; en cambio, para a no hay garantía, porque la reserva de b pudo haber forzado la creación de un nuevo nodo interno y a ya no sería la última asignación en el nodo actual.

El problema se agrava con estructuras como ArrayList o Writer.Allocating, cuyo crecimiento internamente ejecuta allocate + copy + free. Aunque no se intercalen otras reservas, la secuencia garantiza que el bloque antiguo no sea la última asignación: la nueva reserva lo es. El resultado es que la memoria previa queda huérfana hasta que se destruye el arena entero, y en el peor caso se llega a triplicar el consumo.

No existe una solución única, pero hay dos prácticas recomendadas: dimensionar el ArrayList de antemano con initCapacity o ensureTotalCapacityPrecise, y evitar intercalar otras asignaciones entre los appends para favorecer la rama de remap (crecimiento in situ). Estas pautas, además de útiles con ArenaAllocator, mejoran el rendimiento con cualquier asignador.