В го автоматическое управление памятью, поэтому утечек памяти в классическом смысле быть не может (если не использовать пакет unsafe). Но могут быть утечки горутин (когда вы запускаете горутины, но они не завершаются, а блокируются на каком-то io или мьютексе/канале/...). Такое легко ищется с помощью pprof.
Вот как это можно сделать:
1. Добавьте в свою программу веб-интерфейс pprof, запустив любой http-сервер из стандартной библиотеки и добавив импорт:
```go
import (
"net/http"
_ "net/http/pprof"
)
...
func main() {
...
http.ListenAndServe("localhost:8080", nil)
}
```
При запуске программы у вас должен открываться веб-интерфейс pprof по адресу 127.0.0.1:8080/debug/pprof.
2. Дождитесь, когда накопятся утечки и откройте страницу 127.0.0.1:8080/debug/pprof/goroutine?debug=1. На ней будет список всех работающих горутин и их количество. Найдите группу с самым большим количеством, она и утекает. По стеку посмотрите, где горутина блокируется, тогда поймете, почему они накапливаются.
Как найти утечку памяти? Стандартный совет: попробовать собирать с опцией -fsanitize=address или запускать под valgrind.
Интересные статьи на эту тему: [ссылка1](https://www.nylas.com/blog/finding-memory-leak-in-...), [ссылка2](https://www.freecodecamp.org/news/how-i-investigat...).
Дополнительные советы:
1. Проверьте, растет ли потребление памяти постоянно или стабилизируется со временем. Для этого попробуйте уменьшить время задержки (sleep) до секунды вместо минуты.
2. Замените некоторые части кода на заглушки (например, функцию device.getStats() или работу с БД) и проверьте, как изменяется потребление памяти.
3. Избегайте вызова db.Prepare в цикле, так как это может быть бесполезным.
4. Рассмотрите использование переиспользуемого буфера (пула буферов) в функции device.getStats(), чтобы избежать создания новых буферов при каждом вызове ioutil.ReadAll().
5. Используйте возврат nil, err вместо []byte{}, err, так как это более идиоматичный подход.