memory go buffer zlib

memory - No se puede liberar memoria una vez ocupada por bytes.



go buffer (2)

Recibo bytes de texto ASCII comprimido en bytes compressedbytes de tipo [] byte. El problema que enfrento es que el siguiente procedimiento ocupa una gran cantidad de memoria que no se libera después de que la función llega a su fin y permanece ocupada durante todo el tiempo de ejecución del programa.

b := bytes.NewReader(compressedbytes) r, err := zlib.NewReader(b) if err != nil { panic(err) } cleartext, err = ioutil.ReadAll(r) if err != nil { panic(err) }

Noté que el tipo en uso es bytes.Buffer y este tipo tiene las funciones Reset() y Truncate() pero ninguna de ellas permite liberar la memoria que alguna vez bytes.Buffer ocupada.

La documentation de Reset() establece lo siguiente:

Restablecer restablece el búfer para que esté vacío, pero conserva el almacenamiento subyacente para su uso en futuras escrituras. Restablecer es lo mismo que Truncar (0).

¿Cómo puedo desactivar el búfer y volver a liberar la memoria? Mi programa necesita aproximadamente 50 MB de memoria durante la ejecución que dura 2 h. Cuando importo cadenas comprimidas con zlib, el programa necesita 200 MB de memoria.

Gracias por tu ayuda.

=== Actualización

Incluso creé una función separada para la descompresión y llamé al recolector de basura manualmente con runtime.GC() después de que el programa regrese de esa función sin éxito.

// unpack decompresses zlib compressed bytes func unpack(packedData []byte) []byte { b := bytes.NewReader(packedData) r, err := zlib.NewReader(b) if err != nil { panic(err) } cleartext, err := ioutil.ReadAll(r) if err != nil { panic(err) } r.Close() return cleartext }


Algunas cosas para aclarar. Go es un lenguaje de recolección de basura, lo que significa que el recolector de basura libera automáticamente la memoria asignada y utilizada por las variables cuando esas variables se vuelven inalcanzables (si tiene otro puntero a la variable, que todavía cuenta como "accesible").

La memoria liberada no significa que se devuelve al sistema operativo. La memoria liberada significa que la memoria se puede recuperar, reutilizar para otra variable si es necesario. Entonces, desde el sistema operativo, no verá que la memoria disminuya de inmediato solo porque alguna variable se volvió inalcanzable y el recolector de basura detectó esto y liberó la memoria utilizada por él.

Sin embargo, el tiempo de ejecución de Go devolverá la memoria al sistema operativo si no se usa durante algún tiempo (que suele ser de unos 5 minutos). Si el uso de la memoria aumenta durante este período (y opcionalmente se reduce de nuevo), lo más probable es que la memoria no vuelva al sistema operativo.

Si espera un tiempo y no vuelve a asignar memoria, la memoria liberada será devuelta al SO eventualmente (obviamente no todo, pero sí lo serán los "fragmentos grandes" no utilizados). Si no puede esperar a que esto suceda, puede llamar a debug.FreeOSMemory() para forzar este comportamiento:

FreeOSMemory fuerza una recolección de basura seguida de un intento de devolver tanta memoria al sistema operativo como sea posible. (Incluso si esto no se llama, el tiempo de ejecución devuelve gradualmente la memoria al sistema operativo en una tarea en segundo plano).

Echa un vistazo a este tipo de preguntas + respuestas antiguas pero realmente informativas:

Go 1.3 El recolector de basura no libera la memoria del servidor de nuevo al sistema


Eventualmente se lanzará cuando ya nada lo haga referencia, Go tiene un GC bastante decente.