Go GC хранит целые объекты в памяти, а внутренний указатель на одно поле остается? Может ли это вызвать утечку памяти? - PullRequest
0 голосов
/ 06 марта 2019

Сохраняет ли Go GC целые объекты в памяти, а внутренний указатель на поле остается?

Может ли это привести к утечке памяти в подобном коде? Или GC go достаточно «умен», чтобы заметить, что остальная часть объекта больше не нужна, и очистить его из памяти?

package main

import (
    "fmt"
)

const aLot = 500000000

func getInteriorPointer() *int {
    type bigStruct struct {
        someBigThing [aLot]int
        smallThing   int
    }
    b := bigStruct{smallThing: 3}
    return &b.smallThing
}

func main() {
    p := getInteriorPointer()
    // keep using p in the rest of the app, 
    // never using someBigThing from the struct
    fmt.Println(*p)
}

Ответы [ 2 ]

3 голосов
/ 06 марта 2019

Да.Память будет сохраняться до тех пор, пока не останется ни одной ссылки на какую-либо часть выделения.

Обычный пример приведен в уловках срезов

SliceTricks

Удалить без сохранения порядка

a[i] = a[len(a)-1] 
a = a[:len(a)-1]

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

0 голосов
/ 06 марта 2019

Глядя на профилировщик, похоже, что это действительно утечка памяти (go1.11.5 darwin / amd64)


Давайте посмотрим на профилировщик.

Я нашел онлайн-пример для отладки памяти . Приспосабливаясь к моему примеру, я сделал это:

package main

import (
    "fmt"
    "os"
    "runtime"
    "runtime/debug"
    "runtime/pprof"
)

const aLot = 5000000

func getInteriorPointer() *int {
    type bigStruct struct {
        someBigThing [aLot]int
        smallThing   int
    }
    b := bigStruct{smallThing: 3}
    return &b.smallThing
}

func main() {
    p := getInteriorPointer()
    runtime.GC()
    debug.FreeOSMemory()
    fmem, _ := os.Create("prof.prof")
    pprof.WriteHeapProfile(fmem)

    // keep using p in the rest of the app,
    // never using someBigThing from the struct
    fmt.Println(*p)
}

Теперь я бегу go tool pprof prof.prof и list main

ROUTINE ======================== main.getInteriorPointer in /Users/karel/exp/exp.go
   38.15MB    38.15MB (flat, cum)   100% of Total
         .          .     13:func getInteriorPointer() *int {
         .          .     14:   type bigStruct struct {
         .          .     15:           someBigThing [aLot]int
         .          .     16:           smallThing   int
         .          .     17:   }
   38.15MB    38.15MB     18:   b := bigStruct{smallThing: 3}
         .          .     19:   return &b.smallThing
         .          .     20:}
         .          .     21:
         .          .     22:func main() {
         .          .     23:   p := getInteriorPointer()
ROUTINE ======================== main.main in /Users/karel/exp/exp.go
         0    38.15MB (flat, cum)   100% of Total
         .          .     18:   b := bigStruct{smallThing: 3}
         .          .     19:   return &b.smallThing
         .          .     20:}
         .          .     21:
         .          .     22:func main() {
         .    38.15MB     23:   p := getInteriorPointer()
         .          .     24:   runtime.GC()
         .          .     25:   debug.FreeOSMemory()
         .          .     26:   fmem, _ := os.Create("prof.prof")
         .          .     27:   pprof.WriteHeapProfile(fmem)
         .          .     28:

Кажется, сборщик мусора действительно не удаляет ненужный объект из памяти. Если Я правильно понимаю формат. (Возможно, нет, поскольку документации почти нет.)

...