A little bytes here, a little there - and now you are already talking about how memory actually works

My new post was inspired by the latest go quiz. Pay attention to benchmark [1]:







func BenchmarkSortStrings(b *testing.B) {
        s := []string{"heart", "lungs", "brain", "kidneys", "pancreas"}
        b.ReportAllocs()
        for i := 0; i < b.N; i++ {
                sort.Strings(s)
        }
}
      
      





As a convenient wrapper around sort.Sort(sort.StringSlice(s))



, it sort.Strings



modifies the data passed to it, sorting it, so that not everyone (at least, at least 43% of twitter subscribers) could assume that this would lead to allocations [allocations on the heap]. However, at least in recent versions of Go, this is the case and each iteration of this benchmark will cause one allocation. But why?







As many Go developers should know, interfaces are implemented as a two (machine) word structure . Each interface value contains two fields: one contains the type of the value stored by the interface, and the other contains a pointer to that value. [2]







In pseudocode, it would look like this:







type interface struct {
        //    ,  
        type uintptr

        // ()   ,  
        data uintptr
}
      
      





interface.data



, 8 . , , []string



24 : , ; ; (capacity). Go 24 8? , . , []string



24 , *[]string



β€” 8.







[Escaping]



, sort.Strings



:







func BenchmarkSortStrings(b *testing.B) {
        s := []string{"heart", "lungs", "brain", "kidneys", "pancreas"}
        b.ReportAllocs()
        for i := 0; i < b.N; i++ {
                var ss sort.StringSlice = s
                var si sort.Interface = ss // allocation
                sort.Sort(si)
        }
}
      
      





, var si sort.Interface = ss



, var si sort.Interface = &ss



, ss



[3]. , ss



, ? ss



?







, ss



[heap], .







  Total:    296.01MB   296.01MB (flat, cum) 99.66%
      8            .          .           func BenchmarkSortStrings(b *testing.B) { 
      9            .          .             s := []string{"heart", "lungs", "brain", "kidneys", "pancreas"} 
     10            .          .             b.ReportAllocs() 
     11            .          .             for i := 0; i < b.N; i++ { 
     12            .          .                 var ss sort.StringSlice = s 
     13     296.01MB   296.01MB                 var si sort.Interface = ss // allocation 
     14            .          .                 sort.Sort(si) 
     15            .          .             } 
     16            .          .           } 
      
      





, , ss



si



(, , , - ). , ss



. , : ? , .







% go test -bench=. sort_test.go
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-5650U CPU @ 2.20GHz
BenchmarkSortStrings-4          12591951                91.36 ns/op           24 B/op          1 allocs/op
PASS
ok      command-line-arguments  1.260s
      
      





Go 1.16beta1, amd64, 24 [4].







Go 32 .







% go1.15 test -bench=. sort_test.go
goos: darwin
goarch: amd64
BenchmarkSortStrings-4          11453016                96.4 ns/op            32 B/op          1 allocs/op
PASS
ok      command-line-arguments  1.225s
      
      





: Go. , , [size classes].









, , , [] Go 24 . β€” , . , 24 , 24, . , 24 , , . , , .







, Go 24 , , β€” , . , . , . ? , .







, , , "", . , 24 , . ? , β€” [5].







24 , 8 , . 25% "" β€” , , . ? , 9 , ! - ?







, , . 24- , , , . , β€” , , - 24- . Go , ( , , , C++). , .







,



, : ? : . , (, ), . .







[6], ( ) . , [7].







, , 9 . , , , 9- . () , , 4. , β€” . 9 12 . , 3 β€” , , .









. Go 1.15 24 , ss



32 . Martin MΓΆhrmann Go 1.16 24 , .







[1] , . .

[2] Go. , Go 1.15 . -, .

[3] , sort.StringSlice



, *sort.StringSlice



.

[4] 32 , .

[5] 4G (, , 64 ), , [aligment] [padding] ( , , β€” . ).

[6] β€” .

[7] , , .








All Articles