Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String memory usage in Golang

I was optimising a code using a map[string]string where the value of the map was only either "A" or "B". So I thought Obviously a map[string]bool was way better as the map hold around 50 millions elements.

var a = "a"
var a2 = "Why This ultra long string take the same amount of space in memory as 'a'"
var b = true
var c map[string]string
var d map[string]bool

c["t"] = "A"
d["t"] = true

fmt.Printf("a: %T, %d\n", a, unsafe.Sizeof(a))
fmt.Printf("a2: %T, %d\n", a2, unsafe.Sizeof(a2))
fmt.Printf("b: %T, %d\n", b, unsafe.Sizeof(b))
fmt.Printf("c: %T, %d\n", c, unsafe.Sizeof(c))
fmt.Printf("d: %T, %d\n", d, unsafe.Sizeof(d))
fmt.Printf("c: %T, %d\n", c, unsafe.Sizeof(c["t"]))
fmt.Printf("d: %T, %d\n", d, unsafe.Sizeof(d["t"]))

And the result was:

a: string, 8
a2: string, 8
b: bool, 1
c: map[string]string, 4
d: map[string]bool, 4
c2: map[string]string, 8
d2: map[string]bool, 1

While testing I found something weird, why a2 with a really long string use 8 bytes, same as a wich has only one letter ?

like image 664
Dylan Avatar asked Oct 17 '18 09:10

Dylan


People also ask

How does the Golang struct memory layout work?

The Golang struct memory layout starts with the last field, so if you were to look at a string under the microscope, you’d see Len first and then a pointer to the string 's contents. (You can find documentation of these header structs in the reflect package.)

What is string interning in Golang?

golang String interning is a technique of storing only one copy of each unique string in memory. It can significantly reduce memory usage for applications that store many duplicated strings. The built-in string is represented internally as a structure containing two fields.

Are Golang strings immutable?

Golang strings are immutable. In… | by Kalpit Sharma | FAUN Publication Golang strings are immutable. In general, immutable data is simpler to reason about, but it also means your program must allocate more memory to “change” that data. Sometimes, your program can’t afford that luxury. For example, there might not be any more memory to allocate.

How to get the length of a string in Golang?

Strings in Go can be accessed just like an array or a slice. Each byte of string can be accessed in that way. Below is a program showing just that. To get the length of a string we use the len () function. You can compare strings as well. String comparison returns a value of either 0, 1 or -1.


1 Answers

unsafe.Sizeof() does not recursively go into data structures, it just reports the "shallow" size of the value passed. Quoting from its doc:

The size does not include any memory possibly referenced by x. For instance, if x is a slice, Sizeof returns the size of the slice descriptor, not the size of the memory referenced by the slice.

Maps in Go are implemented as pointers, so unsafe.Sizeof(somemap) will report the size of that pointer.

Strings in Go are just headers containing a pointer and a length. See reflect.StringHeader:

type StringHeader struct {
        Data uintptr
        Len  int
}

So unsafe.Sizeof(somestring) will report the size of the above struct, which is independent of the length of the string value (which is the value of the Len field).

To get the actual memory requirement of a map ("deeply"), see How much memory do golang maps reserve? and also How to get memory size of variable in Go?

Go stores the UTF-8 encoded byte sequences of string values in memory. The builtin function len() reports the byte-length of a string, so basically the memory required to store a string value in memory is:

var str string = "some string"

stringSize := len(str) + int(unsafe.Sizeof(str))

Also don't forget that a string value may be constructed by slicing another, bigger string, and thus even if the original string is no longer referenced (and thus no longer needed), the bigger backing array will still be required to be kept in memory for the smaller string slice.

For example:

s := "some loooooooong string"
s2 := s[:2]

Here, even though memory requirement for s2 would be len(s2) + unsafe.Sizeof(str) = 2 + unsafe.Sizeof(str), still, the whole backing array of s will be retained.

like image 194
icza Avatar answered Oct 27 '22 10:10

icza