dongshi8425
dongshi8425
2016-02-18 12:08

在golang程序中查找内存泄漏-reflect.Value.call的含义

I'm trying to find piece of code which is memory leaking.

After launching fresh web application, it's 6 MB. After about 12k requests, it's 28 MB.

I saved its heap just after launching

curl -s localhost:6060/debug/pprof/heap > ~/debug/heavyHeap/6mb.heap

And after 12k requests:

curl -s localhost:6060/debug/pprof/heap > ~/debug/heavyHeap/28mb.heap

Then I am trying to see allocated objects difference:

go tool pprof -alloc_objects -base ~/debug/heavyHeap/6mb.heap $GOPATH/myBin ~/debug/heavyHeap/28mb.heap

Run top command:

Entering interactive mode (type "help" for commands)
(pprof) top
73949086 of 83397023 total (88.67%)
Dropped 299 nodes (cum <= 416985)
Showing top 10 nodes out of 117 (cum >= 1802254)
      flat  flat%   sum%        cum   cum%
  62308988 74.71% 74.71%   62521981 74.97%  reflect.Value.call
   2413961  2.89% 77.61%    2424884  2.91%  calldb.fromToDiff
   1769493  2.12% 79.73%    3796564  4.55%  gopkg.in/mgo.v2/bson.(*decoder).readElemTo
   1622034  1.94% 81.67%    1622034  1.94%  gopkg.in/mgo.v2/bson.(*decoder).readCStr
   1270739  1.52% 83.20%    1401813  1.68%  reflect.(*structType).FieldByNameFunc
   1130028  1.35% 84.55%    1130028  1.35%  reflect.Value.MapKeys
    933704  1.12% 85.67%     933704  1.12%  gopkg.in/mgo.v2/bson.(*decoder).readStr
    927261  1.11% 86.79%     946166  1.13%  fmt.Sprintf
    819209  0.98% 87.77%    1119590  1.34%  my.AnchorWithClassAndDisabledAndStyle

I list the heaviest item reflect.Value.call:

(pprof) list reflect.Value.call
Total: 83397023
ROUTINE ======================== reflect.Value.call in /usr/local/go/src/reflect/value.go
  62308988   62521981 (flat, cum) 74.97% of Total
         .          .    366:   }
         .          .    367: }
         .          .    368: if !isSlice && t.IsVariadic() {
         .          .    369:   // prepare slice for remaining values
         .          .    370:   m := len(in) - n
         .      81921    371:   slice := MakeSlice(t.In(n), m, m)
         .          .    372:   elem := t.In(n).Elem()
         .          .    373:   for i := 0; i < m; i++ {
         .          .    374:     x := in[n+i]
         .          .    375:     if xt := x.Type(); !xt.AssignableTo(elem) {
         .          .    376:       panic("reflect: cannot use " + xt.String() + " as type " + elem.String() + " in " + op)
         .          .    377:     }
         .     131072    378:     slice.Index(i).Set(x)
         .          .    379:   }
         .          .    380:   origIn := in
         .          .    381:   in = make([]Value, n+1)
         .          .    382:   copy(in[:n], origIn)
         .          .    383:   in[n] = slice
         .          .    384: }
         .          .    385:
         .          .    386: nin := len(in)
         .          .    387: if nin != t.NumIn() {
         .          .    388:   panic("reflect.Value.Call: wrong argument count")
         .          .    389: }
         .          .    390: nout := t.NumOut()
         .          .    391:
         .          .    392: // Compute frame type, allocate a chunk of memory for frame
         .          .    393: frametype, _, retOffset, _ := funcLayout(t, rcvrtype)
     32769      32769    394: args := unsafe_New(frametype)
         .          .    395: off := uintptr(0)
         .          .    396:
         .          .    397: // Copy inputs into args.
         .          .    398: if rcvrtype != nil {
         .          .    399:   storeRcvr(rcvr, args)
         .          .    400:   off = ptrSize
         .          .    401: }
         .          .    402: for i, v := range in {
         .          .    403:   v.mustBeExported()
         .          .    404:   targ := t.In(i).(*rtype)
         .          .    405:   a := uintptr(targ.align)
         .          .    406:   off = (off + a - 1) &^ (a - 1)
         .          .    407:   n := targ.size
         .          .    408:   addr := unsafe.Pointer(uintptr(args) + off)
         .          .    409:   v = v.assignTo("reflect.Value.Call", targ, addr)
         .          .    410:   if v.flag&flagIndir != 0 {
         .          .    411:     memmove(addr, v.ptr, n)
         .          .    412:   } else {
         .          .    413:     *(*unsafe.Pointer)(addr) = v.ptr
         .          .    414:   }
         .          .    415:   off += n
         .          .    416: }
         .          .    417:
         .          .    418: // Call.
  62243451   62243451    419: call(fn, args, uint32(frametype.size), uint32(retOffset))
         .          .    420:
         .          .    421: // For testing; see TestCallMethodJump.
         .          .    422: if callGC {
         .          .    423:   runtime.GC()
         .          .    424: }
         .          .    425:
         .          .    426: // Copy return values out of args.
     32768      32768    427: ret := make([]Value, nout)
         .          .    428: off = retOffset
         .          .    429: for i := 0; i < nout; i++ {
         .          .    430:   tv := t.Out(i)
         .          .    431:   a := uintptr(tv.Align())
         .          .    432:   off = (off + a - 1) &^ (a - 1)

But all this stuff don't give a clue where are memory leaks in my code.

What does reflect.Value.call actually mean? I don't remember that I used reflect.Value.call in my code.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • duanfen1992 duanfen1992 5年前

    Package gopkg.in/mgo.v2/bson uses reflection to (un)marshal BSON. But the actual method leaking memory is not shown in the profile because of issue 11786.

    The workaround is to pass the flag -runtime to go tool pprof.

    点赞 评论 复制链接分享

相关推荐