Моя программа golang для профилирования с использованием pprof показывает увеличение памяти в json (* decodeState) objectInterface в пакете std / json - PullRequest
0 голосов
/ 20 июня 2019

У меня есть программа golang, которая использует unmarshall из пакета std "encoding / json", размер которого постоянно увеличивается (утечка памяти). Диаграмма профиля памяти с использованием pprof показывает увеличение памяти в json (* decodeState) objectInterface. Я хочу понять, как и почему это может произойти, чтобы решить проблему.

Я пробовал несколько вещей на верхнем уровне, например, сброс возвращаемого значения, чтобы избежать утечки, но безуспешно.

func (j JSONEncoding) From(b []byte, msg interface{}) (interface{}, error) {
    err := json.Unmarshal(b, &msg)
    return msg, err
}

pprof top5 показывает этот вызов и подробности ниже;

4096.89kB 24.43% 24.43%  4096.89kB 24.43%  encoding/json.(*decodeState).objectInterface

(pprof) list objectInterface
Total: 20.65MB
ROUTINE ======================== encoding/json.(*decodeState).objectInterface in /usr/local/go/src/encoding/json/decode.go
       6MB     7.50MB (flat, cum) 36.32% of Total
         .          .   1061:   return v
         .          .   1062:}
         .          .   1063:
         .          .   1064:// objectInterface is like object but returns map[string]interface{}.
         .          .   1065:func (d *decodeState) objectInterface() map[string]interface{} {
       3MB        3MB   1066:   m := make(map[string]interface{})
         .          .   1067:   for {
         .          .   1068:       // Read opening " of string key or closing }.
.
. deleted code
.
         .          .   1095:
         .          .   1096:       // Read value.
       3MB     4.50MB   1097:       m[key] = d.valueInterface()

используя topN и используя визуализацию, я вижу, как это поле увеличивается со временем / обработкой.

Этот немаршалл вызывается в цикле, но ничего не сохраняется, что может быть причиной утечки. Я не уверен, что и как нужно сделать, чтобы избежать утечки.

Обновление : Утечка памяти была скорее накоплением памяти, в коде в другом месте. При попытке написать минимальный код, который показывает проблему, я не смог воспроизвести, и мне пришлось копать весь код, чтобы узнать, что внутренняя библиотека использует карту для кэширования, а очиститель кэша не работает должным образом.

Моя проблема заключалась в том, что pprof предоставляет информацию о том, кто распределяет, а не где хранится. Я думаю, что мой вопрос должен был быть, как мы можем узнать, какие объекты имеют ссылки какого размера. Я знаю, что одна выделенная ссылка может находиться в нескольких местах, но такая информация легко поможет найти проблему такого рода.

1 Ответ

0 голосов
/ 20 июня 2019

В: Почему бы вам не сделать что-то вроде этого:

https://golang.org/pkg/encoding/json/

func (a *Animal) UnmarshalJSON(b []byte) error {
    var s string
    if err := json.Unmarshal(b, &s); err != nil {
        return err
    }
    switch strings.ToLower(s) {
    default:
        *a = Unknown
    case "gopher":
        *a = Gopher
    case "zebra":
        *a = Zebra
    }

    return nil
}

Другими словами, ваша реализация препятствует объектам (например, "err", например) от мусора?

...