首页 > 解决方案 > 我使用 pprof 进行的 golang 程序分析显示内存在 std/json 包中的 json (* decodeState) objectInterface 处增加

问题描述

我有一个使用 std“encoding/json”包中的 unmarshall 的 golang 程序,它的大小不断增加(内存泄漏)。使用 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,并使用可视化,我可以看到这个框随着时间/处理而增加。

这个 unmarshall 在循环中被调用,但没有保存任何可能是泄漏的原因。我不确定如何以及如何做一些事情来避免这种泄漏。

更新:内存泄漏更多的是内存累积,在其他地方的代码中。在尝试编写显示问题的最小代码时,我无法重现,并且不得不挖掘所有代码以发现内部库正在使用映射来缓存并且缓存清理器无法正常工作。

我的问题是 pprof 正在提供有关谁在分配的信息,而不是它的保存位置。我想我的问题应该是,我们怎样才能找出哪些对象有什么大小的引用。我知道一个分配的参考可能在多个地方,但这些信息很容易帮助找到这类问题。

标签: gomemory-leaksunmarshalling

解决方案


问:你为什么不做这样的事情:

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”)被垃圾收集?


推荐阅读