diff --git a/.chloggen/fix-sharedcomponent-memory-issue.yaml b/.chloggen/fix-sharedcomponent-memory-issue.yaml new file mode 100644 index 00000000000..a4ac09f2493 --- /dev/null +++ b/.chloggen/fix-sharedcomponent-memory-issue.yaml @@ -0,0 +1,25 @@ +# Use this changelog template to create an entry for release notes. + +# One of 'breaking', 'deprecation', 'new_component', 'enhancement', 'bug_fix' +change_type: bug_fix + +# The name of the component, or a single word describing the area of concern, (e.g. otlpreceiver) +component: internal/sharedcomponent + +# A brief description of the change. Surround your text with quotes ("") if it needs to start with a backtick (`). +note: Fixed bug where sharedcomponent would use too much memory remembering all the previously reported statuses + +# One or more tracking issues or pull requests related to the change +issues: [11826] + +# (Optional) One or more lines of additional information to render under the primary note. +# These lines will be padded with 2 spaces and then inserted directly into the document. +# Use pipe (|) for multiline entries. +subtext: + +# Optional: The change log or logs in which this entry should be included. +# e.g. '[user]' or '[user, api]' +# Include 'user' if the change is relevant to end users. +# Include 'api' if there is a change to a library API. +# Default: '[user]' +change_logs: [] diff --git a/internal/sharedcomponent/sharedcomponent.go b/internal/sharedcomponent/sharedcomponent.go index 6c9a94bb6b5..34c63dc66af 100644 --- a/internal/sharedcomponent/sharedcomponent.go +++ b/internal/sharedcomponent/sharedcomponent.go @@ -7,8 +7,8 @@ package sharedcomponent // import "go.opentelemetry.io/collector/internal/sharedcomponent" import ( + "container/ring" "context" - "slices" "sync" "go.opentelemetry.io/collector/component" @@ -77,7 +77,7 @@ func (c *Component[V]) Start(ctx context.Context, host component.Host) error { c.hostWrapper = &hostWrapper{ host: host, sources: make([]componentstatus.Reporter, 0), - previousEvents: make([]*componentstatus.Event, 0), + previousEvents: ring.New(5), } statusReporter, isStatusReporter := host.(componentstatus.Reporter) if isStatusReporter { @@ -108,7 +108,7 @@ var _ componentstatus.Reporter = (*hostWrapper)(nil) type hostWrapper struct { host component.Host sources []componentstatus.Reporter - previousEvents []*componentstatus.Event + previousEvents *ring.Ring lock sync.Mutex } @@ -119,12 +119,10 @@ func (h *hostWrapper) GetExtensions() map[component.ID]component.Component { func (h *hostWrapper) Report(e *componentstatus.Event) { // Only remember an event if it will be emitted and it has not been sent already. h.lock.Lock() - if len(h.sources) > 0 && !slices.Contains(h.previousEvents, e) { - h.previousEvents = append(h.previousEvents, e) + if len(h.sources) > 0 { + h.previousEvents.Value = e + h.previousEvents = h.previousEvents.Next() } - h.lock.Unlock() - - h.lock.Lock() for _, s := range h.sources { s.Report(e) } @@ -133,9 +131,11 @@ func (h *hostWrapper) Report(e *componentstatus.Event) { func (h *hostWrapper) addSource(s componentstatus.Reporter) { h.lock.Lock() - for _, e := range h.previousEvents { - s.Report(e) - } + h.previousEvents.Do(func(a any) { + if e, ok := a.(*componentstatus.Event); ok { + s.Report(e) + } + }) h.lock.Unlock() h.lock.Lock()