memory-management go memory-consumption

memory management - Ir a la gestión del consumo de memoria



memory-management go (2)

Actualmente, go usa un recolector de elementos no utilizados , que en general no define cuándo se descarta el objeto.

Sin embargo, si observa detenidamente, existe una rutina llamada sysmon que se ejecuta esencialmente siempre que su programa lo haga y llama al GC periódicamente:

// forcegcperiod is the maximum time in nanoseconds between garbage // collections. If we go this long without a garbage collection, one // is forced to run. // // This is a variable for testing purposes. It normally doesn''t change. var forcegcperiod int64 = 2 * 60 * 1e9 (...) // If a heap span goes unused for 5 minutes after a garbage collection, // we hand it back to the operating system. scavengelimit := int64(5 * 60 * 1e9)

forcegcperiod determina el período después del cual se llama al GC por la fuerza. scavengelimit determina cuándo se devuelven los intervalos al sistema operativo. Las extensiones son una cantidad de páginas de memoria que pueden contener varios objetos. Se guardan para el tiempo de scavengelimit y se liberan si no hay ningún objeto sobre ellos y se excede scavengelimit .

Más abajo en el código, puede ver que hay una opción de rastreo. Puede usar esto para ver, siempre que el carroñero cree que necesita limpiar:

$ GOGCTRACE=1 go run gc.go gc1(1): 0+0+0 ms 0 -> 0 MB 423 -> 350 (424-74) objects 0 handoff gc2(1): 0+0+0 ms 1 -> 0 MB 2664 -> 1437 (2880-1443) objects 0 handoff gc3(1): 0+0+0 ms 1 -> 0 MB 4117 -> 2213 (5712-3499) objects 0 handoff gc4(1): 0+0+0 ms 2 -> 1 MB 3128 -> 2257 (6761-4504) objects 0 handoff gc5(1): 0+0+0 ms 2 -> 0 MB 8892 -> 2531 (13734-11203) objects 0 handoff gc6(1): 0+0+0 ms 1 -> 1 MB 8715 -> 2689 (20173-17484) objects 0 handoff gc7(1): 0+0+0 ms 2 -> 1 MB 5231 -> 2406 (22878-20472) objects 0 handoff gc1(1): 0+0+0 ms 0 -> 0 MB 172 -> 137 (173-36) objects 0 handoff getting memory gc2(1): 0+0+0 ms 381 -> 381 MB 203 -> 202 (248-46) objects 0 handoff returning memory getting memory returning memory

Como puede ver, no se realiza una invocación de gc entre get y return. Sin embargo, si cambia la demora de 5 segundos a 3 minutos (más de los 2 minutos de forcegcperiod ), el gc eliminará los objetos:

returning memory scvg0: inuse: 1, idle: 1, sys: 3, released: 0, consumed: 3 (MB) scvg0: inuse: 381, idle: 0, sys: 382, released: 0, consumed: 382 (MB) scvg1: inuse: 1, idle: 1, sys: 3, released: 0, consumed: 3 (MB) scvg1: inuse: 381, idle: 0, sys: 382, released: 0, consumed: 382 (MB) gc9(1): 1+0+0 ms 1 -> 1 MB 4485 -> 2562 (26531-23969) objects 0 handoff gc10(1): 1+0+0 ms 1 -> 1 MB 2563 -> 2561 (26532-23971) objects 0 handoff scvg2: GC forced // forcegc (2 minutes) exceeded scvg2: inuse: 1, idle: 1, sys: 3, released: 0, consumed: 3 (MB) gc3(1): 0+0+0 ms 381 -> 381 MB 206 -> 206 (252-46) objects 0 handoff scvg2: GC forced scvg2: inuse: 381, idle: 0, sys: 382, released: 0, consumed: 382 (MB) getting memory

La memoria aún no se ha liberado, pero el GC marcó la región de memoria como no utilizada. La liberación comenzará cuando el tramo utilizado no se use y sea anterior al limit . Del código del carroñero:

if(s->unusedsince != 0 && (now - s->unusedsince) > limit) { // ... runtime·SysUnused((void*)(s->start << PageShift), s->npages << PageShift); }

Este comportamiento puede, por supuesto, cambiar con el tiempo, pero espero que ahora se sienta un poco cuando los objetos se tiran por la fuerza y ​​cuando no.

Como lo señala zupa, la liberación de objetos puede no devolver la memoria al sistema operativo, por lo que es posible que en ciertos sistemas no se produzca un cambio en el uso de la memoria. Este parece ser el caso para Plan 9 y Windows según este hilo en golang-nuts .

Soy nuevo en Ir e intento descubrir cómo maneja el consumo de memoria.

Tengo problemas con la memoria en uno de mis proyectos de prueba. No entiendo por qué Go usa más y más memoria (nunca la libera) cuando mi programa se ejecuta durante mucho tiempo.

Estoy ejecutando el caso de prueba a continuación. Después de la primera asignación, el programa usa casi 350 MB de memoria (según ActivityMonitor). Luego trato de liberarlo y ActivityMonitor muestra que el consumo de memoria se duplica. ¿Por qué?

Estoy ejecutando este código en OS X usando Go 1.0.3.

¿Qué está mal con este código? ¿Y cuál es la forma correcta de administrar grandes variables en los programas Go?

Tuve otro problema relacionado con la gestión de la memoria cuando implementé un algoritmo que usa mucho tiempo y memoria; después de ejecutarlo por un tiempo arroja una excepción de "memoria insuficiente".

package main import ("fmt" "time" ) func main() { fmt.Println("getting memory") tmp := make([]uint32, 100000000) for kk, _ := range tmp { tmp[kk] = 0 } time.Sleep(5 * time.Second) fmt.Println("returning memory") tmp = make([]uint32, 1) tmp = nil time.Sleep(5 * time.Second) fmt.Println("getting memory") tmp = make([]uint32, 100000000) for kk, _ := range tmp { tmp[kk] = 0 } time.Sleep(5 * time.Second) fmt.Println("returning memory") tmp = make([]uint32, 1) tmp = nil time.Sleep(5 * time.Second) return }


Para eventualmente (forzar) recolectar la memoria no utilizada debe llamar a runtime.GC() .

variable = nil puede hacer que las cosas sean inalcanzables y, por lo tanto, elegibles para la recopilación, pero por sí mismo no libera nada.