У меня есть map[string]string
в моем коде. Ключи генерируются в виде случайных строк с помощью функции, подобной NewUUID()
. Однажды я обнаружил, что память долгое время держалась на высоком уровне. Pprof показывает, что большинство (используемых) выделений было выполнено с функцией NewUUID()
. Я думал, что это может быть вызвано этой картой: записи очень часто вставляются и удаляются.
Я видел, что некоторые выводы говорят о том, что при удалении ключа из карты ключ фактически не освобождается, а устанавливает пустой флаг. Понравились эти вопросы:
Безопасно ли удалять выбранные ключи с карты в пределах диапазона?
Нужно ли мне устанавливать карту в ноль, чтобы она собирала мусор?
Но когда я копаюсь в коде в runtime / map_faststr.go (go version: 1.12), я обнаруживаю, что все выглядит не так. Ключ назначается как nil, а значение удаляется через memclrHasPointers
или memclrNoHeapPointers
.
Так какой вывод правильный? Будет ли карта уменьшаться после удаления из нее ключей?
Исходный код map
находится во время выполнения / map_faststr.go
for ; b != nil; b = b.overflow(t) {
for i, kptr := uintptr(0), b.keys(); i < bucketCnt; i, kptr = i+1, add(kptr, 2*sys.PtrSize) {
k := (*stringStruct)(kptr)
if k.len != key.len || b.tophash[i] != top {
continue
}
if k.str != key.str && !memequal(k.str, key.str, uintptr(key.len)) {
continue
}
// Clear key's pointer.
k.str = nil // seams it would be released by GC
v := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
if t.elem.kind&kindNoPointers == 0 { // What kindNoPointers means?
memclrHasPointers(v, t.elem.size)
} else {
memclrNoHeapPointers(v, t.elem.size)
}
b.tophash[i] = emptyOne
...
}
А если ключи действительно отпущены, в чем проблема с моими кодами? Минимальный код подобен следующему:
package main
import (
"math/rand"
"log"
"os"
"os/signal"
//"runtime"
"time"
)
func main() {
log.Println("---start---")
defer log.Println("---end---")
rand.Seed(time.Now().Unix())
go func() {
m := make(map[string]string)
for {
for i := 0; i < 1000000; i++ {
k := randString(64)
m[k] = randString(1024 * 1024)
}
for k, _ := range m {
delete(m, k)
}
//runtime.GC()
}
}()
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, os.Interrupt)
for {
select {
case <- sigs:
log.Println("---Ctrl C recived---")
return
}
}
}
func randString(n int) string {
const letters = "0123456789abcdefgkhijklmnopqrstuvwxyz"
b := make([]byte, n)
for i := 0; i < n; i++ {
b[i] = letters[rand.Int63() % int64(len(letters))]
}
return string(b)
}