dictionary go memory slice

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



memory slice (2)

Tengo curiosidad sobre el costo de memoria del map y el slice , así que escribí un programa para comparar los tamaños. Obtengo el tamaño de la memoria por unsafe.Sizeof(s) Tamaño de la unsafe.Sizeof(s) , pero obviamente está mal, porque cuando cambio el tamaño, la salida es la misma.

func getSlice(size int) []int { t := time.Now() s := make([]int, size*2) for i := 0; i < size; i++ { index := i << 1 s[index] = i s[index+1] = i } fmt.Println("slice time cost: ", time.Since(t)) return s } func getMap(size int) map[int]int { t := time.Now() m := make(map[int]int, size) for i := 0; i < size; i++ { m[i] = i } fmt.Println("map time cost: ", time.Since(t)) return m } func TestMem(t *testing.T) { size := 1000 s := getSlice(size) m := getMap(size) fmt.Printf("slice size: %d/n", unsafe.Sizeof(s)) fmt.Printf("map size: %d/n", unsafe.Sizeof(m)) }


Esta es la forma correcta, utilizando unsafe.Sizeof(s) . Es solo que el resultado seguirá siendo el mismo para un tipo dado: entero, cadena, etc., sin tener en cuenta el valor exacto.

Sizeof toma una expresión x de cualquier tipo y devuelve el tamaño en bytes de una variable hipotética v como si v se declarara mediante var v = x. El tamaño no incluye ninguna memoria posiblemente referenciada por x. Por ejemplo, si x es un segmento, Sizeof devuelve el tamaño del descriptor de segmento, no el tamaño de la memoria a la que hace referencia el segmento.

Referencia unsafe.SizeOf()

Actualizar:

Puede usar la clasificación y luego comparar las representaciones de valores en bytes con Size() . Solo es cuestión de convertir datos en una cadena de bytes.


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

El segmento es una estructura relativamente simple: reflect.SliceHeader , y como sabemos que hace referencia a una matriz de respaldo, 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 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 revise esta pregunta + respuesta: Golang: calcular 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 evaluaciones comparativas de memoria. Pase el argumento -benchmem 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 tiempo e impresión de getSlice() y getMap() por supuesto).

Corriendo con

go test -bench . -benchmem

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 valores B/op indican cuántos bytes se asignaron por operación. allocs/op indica cuántas asignaciones de memoria (distintas) ocurrieron por op.

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