Saltar al contenido

¿Cómo obtener el tamaño de memoria de la variable en Go?

Recuerda que en las ciencias un problema suele tener más de una soluciones, por lo tanto aquí enseñaremos lo más óptimo y mejor.

Solución:

unsafe.SizeOf() y reflect.Type.Size() solo devuelve el tamaño del valor pasado sin atravesar recursivamente la estructura de datos y agregar tamaños de valores puntiagudos.

La rebanada es una estructura relativamente simple: reflect.SliceHeader, y como sabemos que hace referencia a un respaldo array, podemos calcular fácilmente su tamaño “manualmente”, por ejemplo:

s := make([]int32, 1000)

fmt.Println("Size of []int32:", unsafe.Sizeof(s))
fmt.Println("Size of [1000]int32:", unsafe.Sizeof([1000]int32))
fmt.Println("Real size of s:", unsafe.Sizeof(s)+unsafe.Sizeof([1000]int32))

Salida (pruébalo en el Go Playground):

Size of []int32: 12
Size of [1000]int32: 4000
Real size of s: 4012

Los mapas son estructuras de datos mucho más complejas, no entraré en detalles, pero consulte esta pregunta y respuesta: Golang: cálculo de la huella de memoria (o longitud de bytes) de un mapa

Cálculo del tamaño de cualquier variable o estructura (recursivamente)

Si desea números “reales”, puede aprovechar la herramienta de prueba de Go, que también puede realizar pruebas comparativas de memoria. Pasa el -benchmem argumento, y dentro de la función de referencia asigne solo la memoria que desea medir:

func BenchmarkSlice100(b *testing.B) 
    for i := 0; i < b.N; i++  getSlice(100) 

func BenchmarkSlice1000(b *testing.B) 
    for i := 0; i < b.N; i++  getSlice(1000) 

func BenchmarkSlice10000(b *testing.B) 
    for i := 0; i < b.N; i++  getSlice(10000) 

func BenchmarkMap100(b *testing.B) 
    for i := 0; i < b.N; i++  getMap(100) 

func BenchmarkMap1000(b *testing.B) 
    for i := 0; i < b.N; i++  getMap(1000) 

func BenchmarkMap10000(b *testing.B) 
    for i := 0; i < b.N; i++  getMap(10000) 

(Elimine las llamadas de cronometraje e impresión de getSlice() y getMap() por supuesto.)

corriendo con

go test -bench . -benchmem

La salida es:

BenchmarkSlice100-4    3000000        471 ns/op        1792 B/op      1 allocs/op
BenchmarkSlice1000-4    300000       3944 ns/op       16384 B/op      1 allocs/op
BenchmarkSlice10000-4    50000      39293 ns/op      163840 B/op      1 allocs/op
BenchmarkMap100-4       200000      11651 ns/op        2843 B/op      9 allocs/op
BenchmarkMap1000-4       10000     111040 ns/op       41823 B/op     12 allocs/op
BenchmarkMap10000-4       1000    1152011 ns/op      315450 B/op    135 allocs/op

B/op los valores le dicen cuántos bytes se asignaron por operación. allocs/op dice cuántas asignaciones de memoria (distintas) ocurrieron por operación.

En mi arquitectura de 64 bits (donde el tamaño de int es de 8 bytes) indica que el tamaño de un segmento que tiene 2000 elementos es de aproximadamente 16 KB (en línea con 2000 * 8 bytes). Un mapa con 1000 int-int pares requeridos aproximadamente para asignar 42 KB.

Esto genera algunos gastos generales de cálculo de referencias, pero descubrí que es la forma más sencilla durante el tiempo de ejecución de obtener el tamaño de un valor en marcha. Para mis necesidades, la sobrecarga de clasificación no fue un gran problema, así que seguí esta ruta.

func getRealSizeOf(v interface) (int, error) 
    b := new(bytes.Buffer)
    if err := gob.NewEncoder(b).Encode(v); err != nil 
        return 0, err
    
    return b.Len(), nil

Nos puedes auxiliar nuestra ocupación dejando un comentario y puntuándolo te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *