Reducir a 16 bytes un nodo AST en C++: optimizando un parser de Markdown

Fuentes: Optimizing memory use in markdown parser

Un programador documenta el proceso seguido para reducir drásticamente el consumo de memoria de un parser de Markdown escrito en C++, portado desde la librería Rust markdown-rs como parte del proyecto gpui-cpp. La partida fue un struct Node de 232 bytes generado por una IA; el resultado final es un nodo de 16 bytes, con el AST completo comprimido en un arena allocator (bump allocator) que solo crece y se libera reiniciando.

La optimización se aplicó por capas sucesivas, cada una medida con un benchmark que parsea 64 KB de Markdown en cuatro formas (prosa, listas anidadas, tablas GFM y entidades HTML): reordenar los campos del struct y empaquetar seis banderas booleanas en un uint8_t (168→144 bytes); comprimir los punteros del arena a offsets de 4 bytes resueltos con un mapa de offsets; sustituir el par (offset, longitud) de cada cadena por un varint de longitud prepended a los datos (144→112 bytes); reemplazar los vectores de hijos por un anillo de punteros comprimidos, ya que el parser solo añade al final (112→96→80 bytes); comprimir el vector de alineaciones de columnas de las tablas a 2 bits por columna, eliminando un campo que solo usaba Table (80→60 bytes); y, por último, sustituir los ocho campos de cadena fijos por una lista enlazada de cadenas variables dentro del arena, de modo que cada nodo paga solo por las cadenas que usa y un sobrecoste de 5 bytes por cadena presente.

El resultado acumulado recorta entre un 68 % y un 86 % la memoria consumida respecto al punto de partida, sin penalizar el tiempo de parseo. El texto funciona como tutorial práctico: arena allocator, compresión de punteros, reordenación de campos, varints, anillos frente a listas y listas enlazadas de cadenas heterogéneas son las técnicas reutilizables para otros proyectos C++ que gestionen grafos de objetos pequeños.