Middle+
¿Cómo funciona el recolector de basura en el lenguaje Go?
sobes.tech AI
Respuesta de la IA
El recolector de basura en Go implementa un método paralelo, no preciso (no generacional), basado en el algoritmo Mark-and-Sweep con un disparador por volumen de heap.
Principios básicos de funcionamiento:
- Disparador de activación: El recolector se inicia cuando el volumen de memoria asignada por el programa supera un umbral, que se regula dinámicamente.
- Fase de marcado (Mark Phase):
- El recolector pausa solo la parte crítica de la fase de marcado (Stop-the-World, STW), pero esto dura muy poco.
- En paralelo con el programa en ejecución (mutator), el recolector recorre el grafo de objetos desde los punteros raíz (registros, variables globales, pilas de goroutines).
- Los objetos alcanzables (vivos) se marcan como utilizados.
- Fase de barrido (Sweep Phase):
- Tras completar la fase de marcado, el recolector recorre la lista de spans de memoria.
- Los objetos no marcados se consideran basura y su memoria se libera.
- Esta fase también se realiza en paralelo con la ejecución del programa.
- Write Barrier: Go usa una barrera de escritura para rastrear cambios en el grafo de objetos durante la fase de marcado en paralelo. Esto garantiza el correcto funcionamiento del recolector, a pesar de las modificaciones en la memoria por parte del mutator.
- Sin generaciones: A diferencia de otros lenguajes, Go no divide los objetos en generaciones. El recolector procesa toda la heap en su totalidad.
- Meta de baja latencia: Al diseñar el recolector GC de Go, se buscó minimizar las pausas por recolección de basura (STW), haciéndolo adecuado para aplicaciones servidoras.
La paralelización y el uso de la barrera de escritura permiten al recolector minimizar los tiempos de parada del programa, asegurando un alto rendimiento.
Ejemplo de gestión de memoria simplificada (no directamente GC, pero ilustra la liberación de recursos):
package main
import (
"fmt"
"os"
)
func main() {
// Ejemplo de creación de un recurso temporal que será liberado
file, err := os.Create("temp.txt")
if err != nil {
fmt.Println("Error al crear el archivo:", err)
return
}
// Cierre diferido del archivo.
// Aunque esto no es GC en sentido estricto, demuestra la liberación de recursos.
defer file.Close()
fmt.Println("Archivo 'temp.txt' creado.")
// Luego, el programa puede trabajar con el archivo...
// El GC funciona automáticamente en segundo plano para recolectar objetos no utilizados en la heap.
// Por ejemplo, si se crea un slice o un mapa:
data := make([]int, 1000000) // Asignación en la heap
_ = data // Uso
// Cuando data deja de ser alcanzable (por ejemplo, al salir de la función),
// el recolector de basura liberará con el tiempo la memoria asignada.
}