Каждый одноэлементный подсрез удерживает массив на миллион int. На 64-битной платформе десять таких массивов занимают около 76,3 МиБ, плюс прочие объекты.
Определение вывода функции printMemStat() при работе со срезами
Каждый одноэлементный подсрез удерживает массив на миллион int. На 64-битной платформе десять таких массивов занимают около 76,3 МиБ, плюс прочие объекты.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо выяснить, какие значения будет выводить функция printMemStat() на каждой итерации цикла.
func main() {
slices()
}
func slices() {
s := getSubSlice()
printMemStat()
all := make([][]int, 0)
all = append(all, s)
for i := 1; i < 10; i++ {
s2 := getSubSlice()
runtime.GC()
printMemStat()
all = append(all, s2)
}
runtime.GC()
printMemStat()
fmt.Println(all)
}
func getSubSlice() []int {
s := make([]int, 1_000_000)
return s[999_999:]
}
func printMemStat() {
var m runtime.MemStats
runtime.ReadMemStats(&m)
fmt.Println(m.Alloc / 1024 / 1024)
}
Ответ
Каждый одноэлементный подсрез удерживает массив на миллион int. На 64-битной платформе десять таких массивов занимают около 76,3 МиБ, плюс прочие объекты.
После каждого getSubSlice объём живых данных увеличивается примерно на 8 000 000 байт при размере int 8 байт. В цикле all сохраняет ссылки на все массивы, и заключительный fmt.Println делает их нужными до конца функции.
Точные числа Alloc / 1024 / 1024 предсказать нельзя: есть округление, служебные объекты и другие аллокации. runtime.GC не освобождает достижимые массивы. На типичной 32-битной платформе полезные данные вдвое меньше. Чтобы удержать только последний элемент, верните []int{s[len(s)-1]} вместо подсреза.