Будет ли карта уменьшаться после удаления ключей из нее в версии 1.12? - PullRequest
0 голосов
/ 05 июля 2019

У меня есть 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)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...