dictionary - утечки - утечка памяти java




В Go, удаление записи карты указателей вызывает утечку памяти? (2)

первый таймер здесь,

Первое ПРИМЕЧАНИЕ в SliceTricks предполагает, что существует проблема потенциальной проблемы с утечкой памяти при резке или удалении элементов во фрагменте указателей.

То же самое верно для карты? Например: https://play.golang.org/p/67cN0JggWY

Должна ли мы записывать запись перед удалением с карты? Вот так:

m["foo"] = nil

Что делать, если мы просто очистим карту?

m = make(map[string]*myStruct)

Собирает ли сборщик мусора все это?

заранее спасибо


Нет, утечки памяти при удалении с карты не будет.

В случае срезов, поскольку срез фактически использует базовый массив, если существует срез, даже если он использует только один слот в этом массиве - элементы-указатели внутри массива не могут собирать мусор.

« Слайс описывает кусок массива », из которого следует, что массив должен быть там, где существует срез, и его невозможно собрать GC; пока какой-то код указывает на срез.


Проверка источников

Хотя это нигде не документировано, проверьте источники: runtime/hashmap.go , mapdelete() :

558 func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
        // ...
600             memclr(k, uintptr(t.keysize))
601             v := unsafe.Pointer(uintptr(unsafe.Pointer(b)) + dataOffset + bucketCnt*uintptr(t.keysize) + i*uintptr(t.valuesize))
602             memclr(v, uintptr(t.valuesize))
        // ...
618 }

Как вы можете видеть, хранилище для ключа (строка # 600) и значение (строка # 602) очищаются / обнуляются.

Это означает, что если какой-либо из ключей или значений был указателем или если они были значениями сложных типов, содержащих указатели, они обнуляются, и поэтому заостренные объекты больше не ссылаются на внутренние структуры данных карты, поэтому нет памяти утечка здесь.

Когда больше нет ссылки на полное значение map , тогда полная область памяти на map будет собрана мусором, и все указатели, включенные в ключи и значения, также не будут сохранены картой; и если никто другой не ссылается на заостренные объекты, они будут собирать мусор должным образом.

Построение примера для доказательства этого

Мы также можем построить тестовый код, который доказывает это без изучения источников:

type point struct {
    X, Y int
}

var m = map[int]*point{}

func main() {
    fillMap()
    delete(m, 1)
    runtime.GC()
    time.Sleep(time.Second)
    fmt.Println(m)
}

func fillMap() {
    p := &point{1, 2}
    runtime.SetFinalizer(p, func(p *point) {
        fmt.Printf("Finalized: %p %+v\n", p, p)
    })
    m[1] = p
    fmt.Printf("Put in map: %p %+v\n", p, p)
}

Выход (попробуйте на игровой площадке Go ):

Put in map: 0x1040a128 &{X:1 Y:2}
Finalized: 0x1040a128 &{X:1 Y:2}
map[]

Что это делает? Он создает значение *Point (указатель на структуру), помещает его на карту и регистрирует функцию, которая должна вызываться, когда этот указатель становится недоступным (с использованием runtime.SetFinalizer() ), а затем удаляет запись, содержащую этот указатель. Затем мы вызываем runtime.GC() чтобы «принудительно» немедленно собрать мусор. Я также распечатываю карту в конце, чтобы убедиться, что вся карта не является сборкой мусора из-за некоторой оптимизации.

Результат? Мы видим, что вызываемая функция вызывается, что свидетельствует о том, что указатель был удален с карты в результате вызова delete() , потому что (поскольку у нас не было других ссылок на него), он имел право на сбор мусора.





memory-leaks