From 55b5097cc28ae2854de90be8d6d5296eb221fb6b Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 26 Sep 2026 16:23:55 +0000 Subject: [PATCH] fix: release cleared elements in RingBuffer.Clear [patch] Clear only reset the indices, so every reference-type element that was logically removed stayed reachable from the backing array until a later PushBack overwrote its slot. Clear the array first when T holds references, as the Contiguous containers already do. Fixes #72 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01YXTjHR3MfJpmxt8LEwNkjm --- Containers.Test/RingBufferTests.cs | 29 +++++++++++++++++++++++++++++ Containers/RingBuffer.cs | 13 +++++++++++++ 2 files changed, 42 insertions(+) diff --git a/Containers.Test/RingBufferTests.cs b/Containers.Test/RingBufferTests.cs index 569cb26..32af005 100644 --- a/Containers.Test/RingBufferTests.cs +++ b/Containers.Test/RingBufferTests.cs @@ -2,6 +2,7 @@ namespace ktsu.Containers.Tests; +using System.Runtime.CompilerServices; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] @@ -260,6 +261,34 @@ public void Clear_AllowsReuseAfterClearing() Assert.AreEqual(7, buffer.At(0)); } + [TestMethod] + public void Clear_ReleasesReferencesToClearedElements() + { + RingBuffer buffer = new(4); + WeakReference[] references = FillWithUnreferencedObjects(buffer, 3); + + buffer.Clear(); + GC.Collect(); + GC.WaitForPendingFinalizers(); + GC.Collect(); + + Assert.IsFalse(references.Any(r => r.IsAlive)); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static WeakReference[] FillWithUnreferencedObjects(RingBuffer buffer, int count) + { + WeakReference[] references = new WeakReference[count]; + for (int i = 0; i < count; i++) + { + object item = new(); + buffer.PushBack(item); + references[i] = new WeakReference(item); + } + + return references; + } + [TestMethod] public void Constructor_NonPositiveLength_Throws() { diff --git a/Containers/RingBuffer.cs b/Containers/RingBuffer.cs index c4a0f1f..5df3c93 100644 --- a/Containers/RingBuffer.cs +++ b/Containers/RingBuffer.cs @@ -5,6 +5,9 @@ namespace ktsu.Containers; using System.Collections; using System.Diagnostics.CodeAnalysis; using System.Linq; +#if NET5_0_OR_GREATER +using System.Runtime.CompilerServices; +#endif /// /// Represents a fixed-size circular buffer (ring buffer) for storing elements of type . @@ -303,6 +306,16 @@ public IEnumerator GetEnumerator() /// public void Clear() { +#if NET5_0_OR_GREATER + if (RuntimeHelpers.IsReferenceOrContainsReferences()) +#else + if (!typeof(T).IsValueType) +#endif + { + // Clear references so cleared elements can be collected + Array.Clear(Buffer, 0, Buffer.Length); + } + BackIndex = 0; FrontIndex = 0; Count = 0;