From 7c2a91f16925275dbab328824bf962b0d68df93e Mon Sep 17 00:00:00 2001 From: James Crosswell Date: Wed, 19 Jun 2024 11:35:22 +1200 Subject: [PATCH] Fix memory leak when tracing is enabled (#3432) --- CHANGELOG.md | 1 + src/Sentry/TransactionTracer.cs | 25 +++++++++++++++++++ .../Protocol/SentryTransactionTests.cs | 3 ++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dcba610abb..cff383bbf4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ - Fixed Monitor duration calculation ([#3420]https://github.com/getsentry/sentry-dotnet/pull/3420) - Fixed null IServiceProvider in anonymous routes with OpenTelemetry ([#3401](https://github.com/getsentry/sentry-dotnet/pull/3401)) - Fixed Trim warnings in Sentry.DiagnosticSource and WinUIUnhandledException integrations ([#3410](https://github.com/getsentry/sentry-dotnet/pull/3410)) +- Fix memory leak when tracing is enabled ([#3432](https://github.com/getsentry/sentry-dotnet/pull/3432)) ### Dependencies diff --git a/src/Sentry/TransactionTracer.cs b/src/Sentry/TransactionTracer.cs index 6ce9295a76..6b459b767f 100644 --- a/src/Sentry/TransactionTracer.cs +++ b/src/Sentry/TransactionTracer.cs @@ -167,7 +167,11 @@ public IReadOnlyList Fingerprint /// public IReadOnlyDictionary Tags => _tags; +#if NETSTANDARD2_1_OR_GREATER private readonly ConcurrentBag _spans = new(); +#else + private ConcurrentBag _spans = new(); +#endif /// public IReadOnlyCollection Spans => _spans; @@ -337,6 +341,14 @@ public void Push(ISpan span) return null; } } + + public void Clear() + { + lock (_lock) + { + TrackedSpans.Clear(); + } + } } private readonly LastActiveSpanTracker _activeSpanTracker = new LastActiveSpanTracker(); @@ -373,6 +385,9 @@ public void Finish() // Client decides whether to discard this transaction based on sampling _hub.CaptureTransaction(new SentryTransaction(this)); + + // Release tracked spans + ReleaseSpans(); } /// @@ -395,4 +410,14 @@ public void Finish(Exception exception) => /// public SentryTraceHeader GetTraceHeader() => new(TraceId, SpanId, IsSampled); + + private void ReleaseSpans() + { +#if NETSTANDARD2_1_OR_GREATER + _spans.Clear(); +#else + _spans = new ConcurrentBag(); +#endif + _activeSpanTracker.Clear(); + } } diff --git a/test/Sentry.Tests/Protocol/SentryTransactionTests.cs b/test/Sentry.Tests/Protocol/SentryTransactionTests.cs index 80012d33a8..6d33e19a2c 100644 --- a/test/Sentry.Tests/Protocol/SentryTransactionTests.cs +++ b/test/Sentry.Tests/Protocol/SentryTransactionTests.cs @@ -130,7 +130,8 @@ public void Redact_Redacts_Urls() child2.SetExtra("f222", "p111"); child2.Finish(SpanStatus.OutOfRange); - txTracer.Finish(SpanStatus.Aborted); + // Don't finish the tracer - that would cause the spans to be released + // txTracer.Finish(SpanStatus.Aborted); // Act var transaction = new SentryTransaction(txTracer);