Главный перерасход памяти вызван возвратом маленького слайса, удерживающего массив на 100 000 элементов. Скопируйте последний элемент в отдельный слайс или вычислите его напрямую.
Оптимизация и рефакторинг существующего Go‑кода
Главный перерасход памяти вызван возвратом маленького слайса, удерживающего массив на 100 000 элементов. Скопируйте последний элемент в отдельный слайс или вычислите его напрямую.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо выполнить рефакторинг представленного фрагмента программы на Go. Задача подразумевает улучшение читаемости и структуры кода, а также возможную оптимизацию использования памяти. При этом следует оставить всю функциональность без изменений.
func main() {
var mem runtime.MemStats
runtime.ReadMemStats(&mem)
fmt.Printf("Before get(): Alloc = %v MiB\n", mem.Alloc/1024/1024)
resOfRes := make([][]int, 0, 100)
for i := 0; i < 50; i++ {
res := getLastElem()
runtime.GC()
runtime.ReadMemStats(&mem)
fmt.Printf("After getAll(): Alloc = %v MiB, slice: %v\n", mem.Alloc/1024/1024, res)
resOfRes = append(resOfRes, res)
}
fmt.Println()
_ = resOfRes
// Now go into loop
for i := 0; i < 20000; i++ {
runtime.GC()
runtime.ReadMemStats(&mem)
fmt.Printf("Alloc = %v MiB\n", mem.Alloc/1024/1024)
time.Sleep(time.Second * 2)
}
fmt.Println(resOfRes)
}
func getLastElem() []int {
sl := make([]int, 0, 100000)
for i := 0; i < 100000; i++ {
sl = append(sl, i)
}
// return last element
return sl[99999:]
}
В рамках рефакторинга следует обратить внимание на:
- Выделение повторяющихся операций в отдельные функции;
- Улучшение именования переменных и функций для повышения самодокументируемости кода;
- Уменьшение количества прямых вызовов сборщика мусора и измерений памяти, если это не требуется для демонстрации;
- Возможное использование более эффективных способов создания и работы со срезами.
Ответ
Главный перерасход памяти вызван возвратом маленького слайса, удерживающего массив на 100 000 элементов. Скопируйте последний элемент в отдельный слайс или вычислите его напрямую.
При сохранении демонстрационного построения массива верните []int{sl[len(sl)-1]} вместо sl[99999:]. Для точно заданной генерации 0–99999 функционально достаточно return []int{99999}. Ограничение capacity старого среза не освобождает массив. Повтор измерения вынесите в helper; принудительные GC оставляйте только для эксперимента, а не оптимизации рабочего сервиса. resOfRes используется в конце и удерживает все возвращённые массивы.