Fernando Simónes se encontró con inesperadas pausas de recolección de basura de 40ms en un servicio de producción de Go, lo que lo llevó a investigar un problema que se originó en un cgroup que contenía dos procesos: una aplicación Go que realizaba operaciones de io.ReadAll y proto.Unmarshal para crear estructuras de blobs y gráficos, y un servidor HTTP principalmente inactivo. Durante las pausas de recolección de basura, el runtime de Go debe leer sus estructuras de metadatos ubicadas fuera del heap. Simónes descubrió que, bajo presión de memoria, el mecanismo de paginación LRU del kernel movía estas páginas de metadatos al swap. Cuando el recolector de basura intentaba acceder a ellas, cada página generaba un fallo de página importante que requería que el kernel leyera las entradas de la tabla de páginas, invocara do_swap_page, asignara un nuevo marco, lo cargara al cgroup, leyera el contenido de la página, enviara una solicitud de E/S, esperara la finalización de la E/S y restaurara la página en la memoria. Para diagnosticar el problema, Simónes utilizó un script BPF para contar los fallos de página durante los eventos de pausa de paro total. El peor caso mostró que 39.902 microsegundos de la pausa de 40ms fueron consumidos por el manejo de fallos: 228 fallos que representaron 39.013 microsegundos gastados en el manejo de fallos. La salida de addr2line rastreó estos fallos hasta funciones de contabilidad del GC como runtime.(*spanSet).reset, runtime.finishsweep_m y runtime.gcStart.func2. El recolector de basura realiza pausas de paro total en los puntos de terminación de barrido y de marcado. En una prueba de 30 minutos, se produjeron 312 pausas de este tipo, y la demora de 40ms representó 800 veces la mediana de las pausas de 51 microsegundos observadas cuando los metadatos permanecían en memoria. Dado que todos los procesadores (P) se detienen durante estas pausas, cualquier goroutine que esperara una señal de finalización de E/S podría perderla, causando latencia descendente. Además, Simónes señaló que construir un mensaje de 511KiB aumentó de 3-5ms a 105ms en NVMe y 903ms en el volumen de red de Hetzner, aunque no pudo confirmar si este retraso se debió al mismo mecanismo de swap. Una actualización probada con el recolector de basura Green Tea de Go 1.26 mostró un impacto despreciable en el problema de la pausa relacionada con el swap. Los experimentos, incluyendo gráficos, un asignador simulado, scripts BPF y Python, están disponibles en https://github.com/frnsimoes/go-gc-swap-cost. El hallazgo central sigue siendo: swap y el recolector de basura de Go son incompatibles para trabajos de baja latencia, ya que la presión de memoria a nivel del sistema operativo puede inducir pausas de paro total no acotadas a través de la paginación de metadatos.