go: x/tools/gopls: high memory consumption when used with a monorepo

Please answer these questions before submitting your issue. Thanks!

What did you do?

Our code is in a fairly large monorepo containing about 26K files, including vendored packages. I use VSCode, with gopls enabled, and launched from the root of our monorepo, so the workspace includes the whole repo.

What did you expect to see?

gopls using 1-2GB of memory. That’s a wild guess that I can’t really validate, but 8-10 seems excessive.

What did you see instead?

The gopls process is using 8-10GB of memory. This number goes up and down with editor usage, but it never goes below about 6GB, and it generally hovers around 8GB. This is a 16GB laptop, so there’s quite a bit of memory pressure when gopls is running.

Nearly all the code in our monorepo is intended for linux, and this is a mac, so I’ve experimented with adding this setting:

    "gopls": {
        "env": {"GOOS": "linux"}
    },

This does affect the number of errors reported by gopls, but the memory consumption is approximately unchanged.

I also tried building the latest master of gopls using the patch mentioned in this bug: https://github.com/golang/go/issues/37223. This didn’t help either. I’m attaching an SVG heap profile from that version. pprof.zip

Build info

golang.org/x/tools/gopls v0.3.3
    golang.org/x/tools/gopls@v0.3.3 h1:mTFqRDJQmpSsgDDWvbtGnSva1z9uX2XcDszSWa6DhBQ=
    github.com/BurntSushi/toml@v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
    github.com/sergi/go-diff@v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
    golang.org/x/mod@v0.1.1-0.20191105210325-c90efee705ee h1:WG0RUwxtNT4qqaXX3DPA8zHFNm/D9xaBpxzHt1WcA/E=
    golang.org/x/sync@v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
    golang.org/x/tools@v0.0.0-20200227200655-6862ededa516 h1:OX66ZzpltgCOuBSGdaeT77hS2z3ub2AB+EuGxvGRBLE=
    golang.org/x/xerrors@v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
    honnef.co/go/tools@v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
    mvdan.cc/xurls/v2@v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA=

Go info

go version go1.14 darwin/amd64

GO111MODULE="off"
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/geoffhickey/Library/Caches/go-build"
GOENV="/Users/geoffhickey/Library/Application Support/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOINSECURE=""
GONOPROXY="*.internal.digitalocean.com,github.com/digitalocean"
GONOSUMDB="*.internal.digitalocean.com,github.com/digitalocean"
GOOS="darwin"
GOPATH="/Users/geoffhickey/do/cthulhu/docode"
GOPRIVATE="*.internal.digitalocean.com,github.com/digitalocean"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/Cellar/go/1.14/libexec"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.14/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
AR="ar"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
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 -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/v7/w5lfw5qs1bd9np31z9vv04h80000gn/T/go-build021923438=/tmp/go-build -gno-record-gcc-switches -fno-common"

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 8
  • Comments: 54 (24 by maintainers)

Most upvoted comments

I am running in to the same issue described here and it is really annoying because my Linux machine with 8GB memory always runs out of memory and I have to pull out the power plug to be able to actually restart the computer.

This often occurs when i am using vscode and gopls with the https://github.com/fyne-io/fyne repository. I usually see memory slowly but steadily rising up to around five or six gigabytes until the memory in my computer is gone and everything stops functioning as expected. Killing of gopls just makes it rise steadily again. gopls

Using gopls at master hasn’t fixed this issue for me.

I’m working on a monorepo (~40GB in size) and v0.4.4 would regularly cause my remote machine to become unresponsive by using all available memory. I’m now using master which has bought me a little more time but not fixed the issue.

$ gopls version
golang.org/x/tools/gopls master
    golang.org/x/tools/gopls@v0.0.0-20201013053347-2db1cd791039 h1:/32sBC1LOo43X5JHPUZT+hbLpyamXpL4FgR5eMEYb7w=

Gopls now takes quite a little while longer to eat up all my memory but if left unchecked it will do just that. I’m still having to kill it every 3-4 minutes. My solution now is to use a systemd watchdog to kill gopls when memory usage gets too high—not ideal but far better than losing connection to my remote box.

image

golang.org/x/tools/gopls 0.4.1 go version go1.14.2 darwin/amd64 34G too crazy 🤪

Thanks.

Unfortunately I don’t have good news for you. Everything you’ve posted points to expected behavior – I don’t see any signs of a memory leak or work pileup. It looks like the monorepo is simply too large to work with all at once.

If you’re only interested in one folder, you can start VS Code in that folder. If you’re interested in multiple, you can add them piecemeal to your workspace, but note that most gopls features, e.g. find references, will only work within one folder.

There have been a number of memory improvements in gopls at master. Please try out with the instructions on https://github.com/golang/tools/blob/master/gopls/doc/user.md#unstable-versions, or wait for the next release.

I also confirm that it got much better, it became usable with large projects, thank you very much.

@heschik While I appreciate the reply, and forgive my ignorance if this is totally bogus, but would it not be able to reconcile and consolidate the memory for the indexed files? Or would it treat each individual Session as having its own separate set of indexed files? I do understand that it’s technically pre-release and is listed as unstable, so perhaps that isn’t part of its feature set (yet?).

Basically, we have several devs who already use VSCode to run remote to our dev server, which will each therefore run their own separate instance. In theory, even consolidating that to a single instance would at least allow it to not have to reel in the go.mod deps (disk space) and then index that all (memory) per instance.

So considering that, it seems like it could possibly be feasible and incur less overhead than one instance per dev. Sure it would still be O(n*repo), but (in theory, if it works like this), that’s better than O(n* (repo+deps+instance_overhead) ).

Thoughts?

syzkaller is another Go project which causes gopls on my machine to consume 27GiB RAM.