Un peu d'octets ici, un peu là - et maintenant vous parlez déjà du fonctionnement réel de la mémoire

Mon nouveau message a été inspiré par le dernier quiz go. Faites attention au 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)
        }
}
      
      





En guise d'habillage pratique sort.Sort(sort.StringSlice(s))



, il sort.Strings



modifie les données qui lui sont transmises, en les triant, de sorte que tout le monde (au moins, au moins 43% des abonnés Twitter) puisse supposer que cela conduirait à des allocations [allocations sur le tas]. Cependant, au moins dans les versions récentes de Go, c'est le cas et chaque itération de ce benchmark entraînera une allocation. Mais pourquoi?







Comme de nombreux développeurs Go devraient le savoir, les interfaces sont implémentées sous la forme d'une structure à deux mots (machine) . Chaque valeur d'interface contient deux champs: l'un contient le type de valeur stockée par l'interface et l'autre contient un pointeur vers cette valeur. [2]







En pseudocode, cela ressemblerait à ceci:







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