Я записал golang программу, которая использует 1.2 ГБ памяти во времени выполнения.
Вызов go tool pprof http://10.10.58.118:8601/debug/pprof/heap
результаты в дампе с использованием "кучи" только 323.4 МБ.
Используя gcvis
Я получаю это:
.. и эта "куча" формирует профиль:
Вот мой код: https://github.com/sharewind/push-server/blob/v3/broker
Я всегда смущался растущей жилой памятью своих приложений Движения, и наконец я должен был изучить профильные инструменты, которые присутствуют в экосистеме Движения. Время выполнения обеспечивает много метрик в время выполнения. Структура Memstats , но может быть трудно понять, кто из них может помочь узнать причины роста памяти, таким образом, некоторые дополнительные инструменты необходимы.
Профильная среда
Использование https://github.com/tevjef/go-runtime-metrics в Вашем приложении. Например, можно поместить это в Ваш main
:
import(
metrics "github.com/tevjef/go-runtime-metrics"
)
func main() {
//...
metrics.DefaultConfig.CollectionInterval = time.Second
if err := metrics.RunCollector(metrics.DefaultConfig); err != nil {
// handle error
}
}
Выполнение InfluxDB
и Grafana
в Docker
контейнеры:
docker run --name influxdb -d -p 8086:8086 influxdb
docker run -d -p 9090:3000/tcp --link influxdb --name=grafana grafana/grafana:4.1.0
Настроенное взаимодействие между Grafana
и InfluxDB
Grafana
(Grafana основная страница-> Верхний левый угол-> Источники данных-> Добавляют новый источник данных):
панель инструментов Импорта #3242 от [1 123] https://grafana.com (Grafana основная страница-> Верхний левый угол-> Панель инструментов-> Импорт):
Наконец, запустите свое приложение: это передаст метрики во время выполнения к contenerized Influxdb
. Подвергните свое приложение разумной загрузке (в моем случае, это было довольно маленьким - 5 RPS для нескольких часы).
анализ Потребления памяти
Sys
(синоним [1 113]) кривая весьма схожа с [1 114] кривая. Оказывается, что динамическое выделение памяти было основным фактором полного роста памяти, таким образом, небольшой объем памяти, использованной переменными стека, кажется, является постоянным и может быть проигнорирован; HeapIdle
растет с тем же уровнем как Sys
, в то время как HeapReleased
всегда нуль. Очевидно, время выполнения не возвращает память ОС во всем , по крайней мере, при условиях этого теста: HeapIdle minus HeapReleased estimates the amount of memory that could be returned to the OS, but is being retained by the runtime so it can grow the heap without requesting more memory from the OS.
Для тех, кто пытается исследовать проблему потребления памяти, я рекомендовал бы выполнить описанные шаги для исключения некоторых тривиальных ошибок (как утечка goroutine).
память Освобождения явно
интересно, что тот может значительно уменьшить потребление памяти с явными вызовами к [1 118]:
// in the top-level package
func init() {
go func() {
t := time.Tick(time.Second)
for {
<-t
debug.FreeOSMemory()
}
}()
}
На самом деле, этот подход сохранил приблизительно 35% памяти по сравнению с условиями по умолчанию.
Можно также использовать StackImpact, который автоматически отчеты и доклады, которые регулярное и инициированное аномалией выделение памяти представляет к панели инструментов, которые доступны в исторической и сопоставимой форме. Посмотрите это сообщение в блоге для получения дополнительной информации , Обнаружение Утечки памяти в Производстве Идет Приложения
Правовая оговорка: Я работаю на StackImpact