Как управлять сборщиком мусора в GO? Приведите пример с кодом.



Существует параметр, который позволяет управлять сборщиком мусора в Go - это переменная окружения GOGC или ее функциональный аналог SetGCPercent из пакета runtime/debug.



Параметр GOGC определяет процент новой необработанной памяти кучи от живой памяти, при достижении которого будет запущена сборка мусора. Значение GOGC по умолчанию равно 100, что означает, что сборка мусора будет запущена, когда объем новой памяти достигнет 100% от объема живой памяти



Рассмотрим пример программы и отследим изменение размера кучи с помощью инструмента go tool trace. Для запуска программы используем версию Go 1.20.1.



В данном примере, функция performMemoryIntensiveTask использует большое количество памяти размещаемой в куче. Данная функция запускает обработчик с размером очереди NumWorker и количество задач равное NumTasks.



package main



import (

"fmt"

"os"

"runtime/debug"

"runtime/trace"

"sync"

"time"

)



const (

NumWorkers = 4 // Количество воркеров.

NumTasks = 500 // Количество задач.

MemoryIntense = 10000 // Размер память затратной задачи (число элементов).

)



func main() {

// Запись в trace файл.

f, _ := os.Create("trace.out")

trace.Start(f)

defer trace.Stop()



// Установка целевого процента сборщика мусора. По умолчанию 100%.

debug.SetGCPercent(100)



// Очередь задач и очередь результата.

taskQueue := make(chan int, NumTasks)

resultQueue := make(chan int, NumTasks)



// Запуск воркеров.

var wg sync.WaitGroup

wg.Add(NumWorkers)

for i := 0; i < NumWorkers; i++ {

go worker(taskQueue, resultQueue, &wg)

}



// Отправка задач в очередь.

for i := 0; i < NumTasks; i++ {

taskQueue <- i

}

close(taskQueue)



// Получение результатов из очереди.

go func() {

wg.Wait()

close(resultQueue)

}()



// Обработка результатов.

for result := range resultQueue {

fmt.Println("Результат:", result)

}



fmt.Println("Готово!")

}



// Функция воркера.

func worker(tasks <-chan int, results chan<- int, wg *sync.WaitGroup) {

defer wg.Done()



for task := range tasks {

result := performMemoryIntensiveTask(task)

results <- result

}

}



// performMemoryIntensiveTask функция требующая много памяти.

func performMemoryIntensiveTask(task int) int {

// Создание среза большого размера.

data := make([]int, MemoryIntense)

for i := 0; i < MemoryIntense; i++ {

data[i] = i + task

}



// Имитация временной задержки

time.Sleep(10 * time.Millisecond)



// Вычисление результата.

result := 0

for _, value := range data {

result += value

}

return result

}


Для трассировки работы программы результат записывается в файл trace.out:



// Запись в trace файл.

f, _ := os.Create("trace.out")

trace.Start(f)

defer trace.Stop()


Используя инструмент go tool trace, мы можем наблюдать за изменениями размера кучи и анализировать поведение сборщика мусора в вашей программе.



Hidden text

Обратите внимание, что точные детали и возможности инструмента go tool trace могут варьироваться в разных версиях Go, поэтому рекомендуется обратиться к официальной документации для получения более подробной информации о его использовании в вашей конкретной версии Go.



 Статья



@golang_interview