From 89fee75c632051ecc7bd1e07b148567aae8bbb17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Sun, 24 Sep 2023 00:42:02 -0400 Subject: [PATCH 1/3] Fix memory leak in MemoryCache `WeakReference.TryGetTarget` apparently returns false in the target object's finalizer. Here is an example demonstrating that: ```cs CreateTest(); GC.Collect(GC.MaxGeneration); GC.WaitForPendingFinalizers(); void CreateTest() => _ = new Test(); class Test { private readonly WeakReference _wr; public Test() { _wr = new WeakReference(this); Console.WriteLine(_wr.TryGetTarget(out _)); // True } ~Test() { Console.WriteLine(_wr.TryGetTarget(out _)); // False } } ``` In MemoryCache that would cause the Stats in the _allStats list to never be cleaned out. --- .../Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs index 24212fbc65c684..526c28d2999573 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs @@ -389,10 +389,9 @@ private void RemoveFromStats(Stats current) { for (int i = 0; i < _allStats.Count; i++) { - if (_allStats[i].TryGetTarget(out Stats? stats) && stats == current) + if (_allStats[i].TryGetTarget(out Stats? stats)) { _allStats.RemoveAt(i); - break; } } From d4bbc751280b4a690d8db35efff1e156c4d4158f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Sun, 24 Sep 2023 15:15:42 -0400 Subject: [PATCH 2/3] Invert condition --- .../Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs index 526c28d2999573..d2f8b016d944b7 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs @@ -389,7 +389,7 @@ private void RemoveFromStats(Stats current) { for (int i = 0; i < _allStats.Count; i++) { - if (_allStats[i].TryGetTarget(out Stats? stats)) + if (!_allStats[i].TryGetTarget(out Stats? stats)) { _allStats.RemoveAt(i); } From 99941dd274b5889111b3f751f68b00bb179b9226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire?= Date: Mon, 16 Oct 2023 10:56:13 -0400 Subject: [PATCH 3/3] Update MemoryCache.cs --- .../Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs index d2f8b016d944b7..2188cdd302a831 100644 --- a/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs +++ b/src/libraries/Microsoft.Extensions.Caching.Memory/src/MemoryCache.cs @@ -392,6 +392,7 @@ private void RemoveFromStats(Stats current) if (!_allStats[i].TryGetTarget(out Stats? stats)) { _allStats.RemoveAt(i); + i--; } }