Open srosenberg opened 1 year ago
cc @cockroachdb/test-eng
semgrep
was invoked via the following,
NO_COLOR=true semgrep --verbose --config ~/.semgrep/rules/missing_stop.yml pkg/ >~/missing_stop_out.txt
NOTE: rename the attached to missing_stop.yml
.
The example below [1] is based on [2]. It first allocates 100,000 Ticker
s, one per goroutine. Subsequently, each goroutine exits while the tickers leak. The result is high cpu utilization,
go run leaking_timer.go
Making 100000 tickers
Total heap: 48111384
Sleeping... check CPU utilization
PID COMMAND %CPU
88757 leaking_timer 131.6
Rerunning the above after uncommenting defer t.Stop()
yields,
PID COMMAND %CPU TIME
89379 leaking_timer 1.7
[1] https://gist.github.com/srosenberg/a4b920560f61c1f8a41869dfaed051bc [2] https://github.com/golang/go/issues/11662#issue-94398002
We have marked this issue as stale because it has been inactive for 18 months. If this issue is still relevant, removing the stale label or adding a comment will keep it active. Otherwise, we'll close it in 10 days to keep the issue queue tidy. Thank you for your contribution to CockroachDB!
Background
The official API documentation [1] for
time.NewTicker
states,The included example illustrates correct usage, namely,
defer
,It may seem that GC would come to the rescue in cases where
Stop
is missing. After all, forgetting toClose
the file descriptor fromos.OpenFile
doesn't result in a permanent resource leak. This is becauseruntime.SetFinalizer
will eventually invokeClose
on GCed file descriptors. Unfortunately, this doesn't hold forTicker
(orTimer
) [2]. The runtime stores (active) timers in heap that's attached to a specificP
, in thetimers
array. Thus, timers cannot be completely GCed. They must be explicitly removed from heap viadeltimer
[3];Stop
is essentially a wrapper for it. IfStop
is never invoked, both memory and CPU resources end up leaking.While the memory footprint of a single
Ticker
(orTimer
) is constant and negligible, it may require a non-constant amount of CPU work to keep ticking. Consequently, a large number of leakedTicker
s can result in a non-trivial increase of CPU utilization. (Example below illustrates a high CPU utilization.)Preliminary Finding
A preliminary investigation using
semgrep
(rules attached) revealed potentialTicker
andTimer
leaks,t
inchaosLoop
ticker
injobSurvivesNodeShutdown
timer
inrun
timer.Stop
is invokedticker
inmakeCSVReporter
ticker
inaddToPurgatoryLocked
t
inheartbeatLoop
timer
inrun
timer
instartResolver
NOTE: this is not the first time
Ticker
leak was identified [4]. Hence, as the codebase continues to evolve, we should attempt to catch it statically.[1] https://pkg.go.dev/time#NewTicker [2] https://github.com/golang/go/issues/8001 [3] https://github.com/golang/go/blob/master/src/runtime/time.go#L314 [4] https://github.com/cockroachdb/cockroach/pull/1201
Jira issue: CRDB-20387