diff --git a/CHANGELOG.md b/CHANGELOG.md index 6b9589f30532..5773e6c79ecd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm - Support scope attributes and make them as identifying for `Meter` in `go.opentelemetry.io/otel` and `go.opentelemetry.io/otel/sdk/metric`. (#5926) - Support scope attributes and make them as identifying for `Logger` in `go.opentelemetry.io/otel` and `go.opentelemetry.io/otel/sdk/log`. (#5925) - Make schema URL and scope attributes as identifying for `Tracer` in `go.opentelemetry.io/otel/bridge/opentracing`. (#5931) +- Clear unneeded slice elements to allow GC to collect the objects in `go.opentelemetry.io/otel/sdk/log`, `go.opentelemetry.io/otel/metric`, and `go.opentelemetry.io/otel/trace`. (#5804) ### Removed diff --git a/sdk/log/record.go b/sdk/log/record.go index ea842660b0bc..155e4cad2b6e 100644 --- a/sdk/log/record.go +++ b/sdk/log/record.go @@ -234,7 +234,7 @@ func (r *Record) AddAttributes(attrs ...log.KeyValue) { // // Do not use head(attrs, r.attributeCountLimit - n) here. If // (r.attributeCountLimit - n) <= 0 attrs needs to be emptied. - last := max(0, (r.attributeCountLimit - n)) + last := max(0, r.attributeCountLimit-n) r.addDropped(len(attrs) - last) attrs = attrs[:last] } diff --git a/sdk/metric/internal/aggregate/drop.go b/sdk/metric/internal/aggregate/drop.go index 76d52839b604..8396faaa4aec 100644 --- a/sdk/metric/internal/aggregate/drop.go +++ b/sdk/metric/internal/aggregate/drop.go @@ -22,5 +22,6 @@ func (r *dropRes[N]) Offer(context.Context, N, []attribute.KeyValue) {} // Collect resets dest. No exemplars will ever be returned. func (r *dropRes[N]) Collect(dest *[]exemplar.Exemplar) { + clear(*dest) // Erase elements to let GC collect objects *dest = (*dest)[:0] } diff --git a/sdk/metric/internal/aggregate/exemplar.go b/sdk/metric/internal/aggregate/exemplar.go index dcb899d62677..435462577dd8 100644 --- a/sdk/metric/internal/aggregate/exemplar.go +++ b/sdk/metric/internal/aggregate/exemplar.go @@ -17,6 +17,7 @@ var exemplarPool = sync.Pool{ func collectExemplars[N int64 | float64](out *[]metricdata.Exemplar[N], f func(*[]exemplar.Exemplar)) { dest := exemplarPool.Get().(*[]exemplar.Exemplar) defer func() { + clear(*dest) // Erase elements to let GC collect objects *dest = (*dest)[:0] exemplarPool.Put(dest) }() diff --git a/sdk/metric/pipeline.go b/sdk/metric/pipeline.go index 7e85bd2dc981..6aa6426bf2af 100644 --- a/sdk/metric/pipeline.go +++ b/sdk/metric/pipeline.go @@ -115,6 +115,7 @@ func (p *pipeline) produce(ctx context.Context, rm *metricdata.ResourceMetrics) } if err := ctx.Err(); err != nil { rm.Resource = nil + clear(rm.ScopeMetrics) // Erase elements to let GC collect objects rm.ScopeMetrics = rm.ScopeMetrics[:0] return err } @@ -128,6 +129,7 @@ func (p *pipeline) produce(ctx context.Context, rm *metricdata.ResourceMetrics) if err := ctx.Err(); err != nil { // This means the context expired before we finished running callbacks. rm.Resource = nil + clear(rm.ScopeMetrics) // Erase elements to let GC collect objects rm.ScopeMetrics = rm.ScopeMetrics[:0] return err } diff --git a/sdk/trace/batch_span_processor.go b/sdk/trace/batch_span_processor.go index 4ce757dfd6b1..ccc97e1b6625 100644 --- a/sdk/trace/batch_span_processor.go +++ b/sdk/trace/batch_span_processor.go @@ -280,6 +280,7 @@ func (bsp *batchSpanProcessor) exportSpans(ctx context.Context) error { // // It is up to the exporter to implement any type of retry logic if a batch is failing // to be exported, since it is specific to the protocol and backend being sent to. + clear(bsp.batch) // Erase elements to let GC collect objects bsp.batch = bsp.batch[:0] if err != nil { diff --git a/sdk/trace/span.go b/sdk/trace/span.go index 730fb85c3ef6..4f1a6c76eb7b 100644 --- a/sdk/trace/span.go +++ b/sdk/trace/span.go @@ -639,10 +639,7 @@ func (s *recordingSpan) dedupeAttrsFromRecord(record map[attribute.Key]int) { record[a.Key] = len(unique) - 1 } } - // s.attributes have element types of attribute.KeyValue. These types are - // not pointers and they themselves do not contain pointer fields, - // therefore the duplicate values do not need to be zeroed for them to be - // garbage collected. + clear(s.attributes[len(unique):]) // Erase unneeded elements to let GC collect objects s.attributes = unique }