Определение вывода функции printMemStat() при работе со срезами

Каждый одноэлементный подсрез удерживает массив на миллион int. На 64-битной платформе десять таких массивов занимают около 76,3 МиБ, плюс прочие объекты.

Короткий ответ

Что ответить на собеседовании

Каждый одноэлементный подсрез удерживает массив на миллион 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]} вместо подсреза.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее