You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We run https://github.com/cesanta/docker_auth/ (which uses this package) and noticed a memory leak. If you check the heap - most of the memory is used by runtime.malg. If you then check goroutines, iterate holds most of them:
$ go tool pprof 2024-09-07T16:13:49+1000_goroutine.outFile: auth_serverBuild ID: f0023e9b8e89438ff941b55f3266cd69dfff1f88Type: goroutineTime: Sep 7, 2024 at 4:13pm (AEST)Entering interactive mode (type "help" for commands, "o" for options)(pprof) top5Showing nodes accounting for 10539, 100% of 10542 totalDropped 45 nodes (cum <= 52)Showing top 5 nodes out of 9 flat flat% sum% cum cum% 10539 100% 100% 10539 100% runtime.gopark 0 0% 100% 4889 46.38% github.com/schwarmco/go-cartesian-product.Iter.func1 0 0% 100% 5638 53.48% github.com/schwarmco/go-cartesian-product.iterate 0 0% 100% 5638 53.48% runtime.chansend 0 0% 100% 5638 53.48% runtime.chansend1(pprof)
I created a new func that takes a context arg, and changed Iter to use default context:
diff --git a/cartesian.go b/cartesian.go
index 2a64b73..80e2965 100644
--- a/cartesian.go+++ b/cartesian.go@@ -1,28 +1,47 @@
package cartesian
+import "context"+
// Iter takes interface-slices and returns a channel, receiving cartesian products
func Iter(params ...[]interface{}) chan []interface{} {
- // create channel+ return IterWithContext(context.Background(), params...)+}++func IterWithContext(ctx context.Context, params ...[]interface{}) <-chan []interface{} {
c := make(chan []interface{})
+
if len(params) == 0 {
close(c)
- return c // Return a safe value for nil/empty params.+ return c
}
+
go func() {
- iterate(c, params[0], []interface{}{}, params[1:]...)- close(c)+ defer close(c) // Ensure the channel is closed when the goroutine exits++ iterate(ctx, c, params[0], []interface{}{}, params[1:]...)
}()
+
return c
}
-func iterate(channel chan []interface{}, topLevel, result []interface{}, needUnpacking ...[]interface{}) {+func iterate(ctx context.Context, channel chan []interface{}, topLevel, result []interface{}, needUnpacking ...[]interface{}) {
if len(needUnpacking) == 0 {
for _, p := range topLevel {
- channel <- append(append([]interface{}{}, result...), p)+ select {+ case <-ctx.Done():+ return // Exit if the context is canceled+ case channel <- append(append([]interface{}{}, result...), p):+ }
}
return
}
+
for _, p := range topLevel {
- iterate(channel, needUnpacking[0], append(result, p), needUnpacking[1:]...)+ select {+ case <-ctx.Done():+ return // Exit if the context is canceled+ default:+ iterate(ctx, channel, needUnpacking[0], append(result, p), needUnpacking[1:]...)+ }
}
}
I suspect this might be a common problem where consumers don't wait for all the data to be written to the channel and the channel to close before moving on, and are leaking goroutines.
Let me know what you think and if you want me to raise a PR, thanks!
The text was updated successfully, but these errors were encountered:
We run https://github.com/cesanta/docker_auth/ (which uses this package) and noticed a memory leak. If you check the heap - most of the memory is used by
runtime.malg
. If you then checkgoroutines
,iterate
holds most of them:Thats because it calls Iter and then breaks on a match: https://github.com/cesanta/docker_auth/blob/main/auth_server/authz/acl.go#L183-L192 .
iterate
will block on trying toappend
: https://github.com/schwarmco/go-cartesian-product/blob/master/cartesian.go#L21 - but nothing will ever read from that channel.I created a new func that takes a context arg, and changed Iter to use default context:
I suspect this might be a common problem where consumers don't wait for all the data to be written to the channel and the channel to close before moving on, and are leaking goroutines.
Let me know what you think and if you want me to raise a PR, thanks!
The text was updated successfully, but these errors were encountered: