Skip to content

runtime: mallocgc leaks memory due to profilealloc when MemProfileRate is > 0 which is true by default #42347

Closed
@leighhopcroft

Description

@leighhopcroft

What version of Go are you using (go version)?

$ go version
go version go1.15.3 linux/amd64

Does this issue reproduce with the latest release?

yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
GO111MODULE="auto"
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/go/pkg/mod"
GONOPROXY="gitlab.corp.wabtec.com"
GONOSUMDB="gitlab.corp.wabtec.com"
GOOS="linux"
GOPATH="/go"
GOPRIVATE="gitlab.corp.wabtec.com"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/workspaces/rm-edge-hst/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build132198306=/tmp/go-build -gno-record-gcc-switches"

What did you do?

I reviewed the runtime source as I was looking for a stubborn memory leak in a long running process and discovered a code path that I think leaks memory. @josharian Encouraged me to raise an issue here after discussion on gophers slack #performance channel.

What did you expect to see?

No indefinite repeated calls to runtime.persistentalloc in a long running process.

What did you see instead?

  1. runtime.MemProfileRate int = 512 * 1024 by default i.e. > 0 (https://golang.org/src/runtime/mprof.go?h=MemProfileRate#L493)
  2. mallocgc will therefore call profilealloc periodically due to MemProfileRate > 0 (https://golang.org/src/runtime/malloc.go?h=profilealloc#L1140)
  3. profilealloc will call mProf_Malloc (https://golang.org/src/runtime/malloc.go?h=mProf_Malloc#L1236)
  4. mProf_Malloc will call stkbucket (https://golang.org/src/runtime/mprof.go?h=stkbucket#L344)
  5. stkbucket will call newBucket (https://golang.org/src/runtime/mprof.go?h=newBucket#L240)
  6. newBucket will call persistentalloc with size equal to unsafe.Sizeof(bucket{}) + uintptr(nstk)*unsafe.Sizeof(uintptr(0)) + unsafe.Sizeof(memRecord{}) (https://golang.org/src/runtime/mprof.go?h=persistentalloc#L173)

So, even if nstk == 0 the minimum persistent allocation would be unsafe.Sizeof(bucket{}) + unsafe.Sizeof(memRecord{}) which is 144 bytes (https://play.golang.org/p/5JCqMHh_2aO). If I have understood this correctly, this means that we are guaranteed to leak at least 144 bytes every MemProfileRate by default.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions