What version of Go are you using (go version)?
$ go version
go version go1.19.2 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=""
GOARCH="amd64"
GOBIN=""
GOCACHE=""
GOENV=""
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE=""
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH=""
GOPRIVATE=""
GOPROXY=""
GOROOT="/usr/lib/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.19.2"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/tmp/bug/go.mod"
GOWORK=""
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 -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build3528461531=/tmp/go-build -gno-record-gcc-switches"
What did you do?
After mass-upgrading dependencies in a proprietary HTTP + gRPC reverse proxy, I observed unbounded memory growth when serving gRPC streams.
The full data flow is:
gRPC client stream -> gRPC proxy -> gRPC service stream
The implicated component that depends on x/net and observing the memory leak is the gRPC proxy.
I bisected the behavior to 2e0b12c274b70e5e836cf4bb0cda99c44f61a4d1 from golang.org/x/net. Prior to this commit, memory usage while serving unidirectional (client -> server) streams remained constant. At this commit and later, memory usage grows consistently as long as the stream is active.
Please see #56315 (comment) for a minimally complete example of the data flow described above that demonstrates the bug.
The client logic is to repeatedly send messages to the server over a unidirectional stream, each about 32 KB in size. The server logic is to read the message and noop (discard the data).
I don't have enough knowledge of the HTTP/2 specification to do any investigation into 2e0b12c274b70e5e836cf4bb0cda99c44f61a4d1 itself, so I don't have an RCA.
What did you expect to see?
I expected to be able to serve the gRPC stream without unbounded memory growth.
What did you see instead?
I observe what appears to be a memory leak regression starting from this commit.
I verified this behavior by watching pmap -x $(pidof ...) over time for the good/bad commits identified by bisect against the same client logic.
After running the test workload:
Here is an example heap usage graph captured with pprof at version v0.0.0-20220920183852-bf014ff85ad5.
Here is an example heap usage graph captured with pprof at version v0.0.0-20221019024206-cb67ada4b0ad.
cc @neild
What version of Go are you using (
go version)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env)?go envOutputWhat did you do?
After mass-upgrading dependencies in a proprietary HTTP + gRPC reverse proxy, I observed unbounded memory growth when serving gRPC streams.
The full data flow is:
The implicated component that depends on
x/netand observing the memory leak is the gRPC proxy.I bisected the behavior to
2e0b12c274b70e5e836cf4bb0cda99c44f61a4d1fromgolang.org/x/net. Prior to this commit, memory usage while serving unidirectional (client -> server) streams remained constant. At this commit and later, memory usage grows consistently as long as the stream is active.Please see #56315 (comment) for a minimally complete example of the data flow described above that demonstrates the bug.
The client logic is to repeatedly send messages to the server over a unidirectional stream, each about 32 KB in size. The server logic is to read the message and noop (discard the data).
I don't have enough knowledge of the HTTP/2 specification to do any investigation into 2e0b12c274b70e5e836cf4bb0cda99c44f61a4d1 itself, so I don't have an RCA.
What did you expect to see?
I expected to be able to serve the gRPC stream without unbounded memory growth.
What did you see instead?
I observe what appears to be a memory leak regression starting from this commit.
I verified this behavior by watching
pmap -x $(pidof ...)over time for the good/bad commits identified by bisect against the same client logic.After running the test workload:
Here is an example heap usage graph captured with pprof at version
v0.0.0-20220920183852-bf014ff85ad5.Here is an example heap usage graph captured with pprof at version
v0.0.0-20221019024206-cb67ada4b0ad.cc @neild