Objetos de pool y asignación estática: un enfoque para evitar errores de memoria en motores de trading
El uso de pools de objetos y la asignación estática puede eliminar las fallas de uso después de liberar y la confusión de tipos en sistemas críticos.
Problema de memoria en motores de matching
En un motor de matching de órdenes, un error de use‑after‑free surgió cuando una orden cancelada se liberaba de la pool y, sin haber sido retirada de su nivel de precio, era reutilizada para una nueva orden. El puntero quedó apuntando a datos que ya no pertenecían a la misma estructura, generando un comportamiento indefinido.
El núcleo del problema es la ausencia de un mecanismo de generación en la pool: cada slot se reutiliza sin saber a qué generación de objeto corresponde.
¿Qué aporta una pool tipada?
Si el alocador acepta un parámetro de tipo T en tiempo de compilación o en tiempo de ejecución, se puede construir un pool segregado por tipo. Cada pool mantiene objetos de un único tipo, evitando que un puntero de tipo T1 sea interpretado como T2.
Ventajas:
- Se elimina la confusión de tipos.
- Se gana localidad de memoria, pues los objetos del mismo tipo se agrupan.
- El coste de la sobrecarga de memoria suele ser marginal, ya que tipos poco frecuentes no ocupan espacio adicional.
Desventajas:
- Se pierde la reutilización cruzada entre tipos, lo que puede incrementar la huella de memoria.
- Los enums en línea siguen siendo un punto débil; si se heap‑allocan, el problema desaparece.
Asignación estática: la solución de “no más dinámico”
Una alternativa radical es la asignación estática. Al iniciar el motor se reserva un número fijo de órdenes: --orders-max=1_000_000. Si se recibe más, se rechaza la solicitud.
Ventajas:
- El sistema no fallará por falta de memoria en tiempo de ejecución.
- Se evita la activación del OOM killer del kernel.
- La carga de trabajo siempre se mantiene dentro de los límites predefinidos.
Desventajas:
- Si el número máximo es subestimado, se perderán solicitudes.
- La memoria se reserva de forma anticipada, lo que puede ser ineficiente en entornos con variabilidad alta.
Pool con “reserved” como valor neutro
En lugar de limitar la cantidad, se puede mantener un número fijo de órdenes y usar un valor neutro (reserved) para marcar las que están libres. Cada orden siempre existe, simplemente circula entre estados.
Esto reduce la complejidad cognitiva: el programador ya no necesita crear y destruir órdenes, sino moverlas de un estado a otro. La coherencia de los datos se mantiene porque cada slot sigue perteneciendo al mismo tipo.
Conclusión
El uso de pools tipados o la asignación estática son técnicas maduras que reducen la superficie de ataque de errores de memoria en sistemas críticos. En entornos de alto rendimiento, la elección depende de la tolerancia a la fragmentación y la variabilidad de carga. La próxima iteración debe incluir métricas de latencia y uso de memoria para decidir entre un pool genérico o una reserva estática.
