Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 7882fbe

Browse files
benaadamskarelz
authored andcommitted
Don't capture AsyncLocals into MemoryCache timer (#26077)
Don't capture AsyncLocals into MemoryCache timer
1 parent 207618d commit 7882fbe

File tree

2 files changed

+39
-2
lines changed

2 files changed

+39
-2
lines changed

src/System.Runtime.Caching/src/System/Runtime/Caching/CacheExpires.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -896,8 +896,26 @@ internal void EnableExpirationTimer(bool enable)
896896
{
897897
DateTime utcNow = DateTime.UtcNow;
898898
TimeSpan due = _tsPerBucket - (new TimeSpan(utcNow.Ticks % _tsPerBucket.Ticks));
899-
Timer timer = new Timer(new TimerCallback(this.TimerCallback), null,
899+
Timer timer;
900+
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
901+
bool restoreFlow = false;
902+
try
903+
{
904+
if (!ExecutionContext.IsFlowSuppressed())
905+
{
906+
ExecutionContext.SuppressFlow();
907+
restoreFlow = true;
908+
}
909+
910+
timer = new Timer(new TimerCallback(this.TimerCallback), null,
900911
due.Ticks / TimeSpan.TicksPerMillisecond, _tsPerBucket.Ticks / TimeSpan.TicksPerMillisecond);
912+
}
913+
finally
914+
{
915+
// Restore the current ExecutionContext
916+
if (restoreFlow)
917+
ExecutionContext.RestoreFlow();
918+
}
901919
_timerHandleRef = new GCHandleRef<Timer>(timer);
902920

903921
Dbg.Trace("Cache", "Cache expiration timer created.");

src/System.Runtime.Caching/src/System/Runtime/Caching/MemoryCacheStatistics.cs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,26 @@ private void InitDisposableMembers()
155155
try
156156
{
157157
_cacheMemoryMonitor = new CacheMemoryMonitor(_memoryCache, _configCacheMemoryLimitMegabytes);
158-
Timer timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval);
158+
Timer timer;
159+
// Don't capture the current ExecutionContext and its AsyncLocals onto the timer causing them to live forever
160+
bool restoreFlow = false;
161+
try
162+
{
163+
if (!ExecutionContext.IsFlowSuppressed())
164+
{
165+
ExecutionContext.SuppressFlow();
166+
restoreFlow = true;
167+
}
168+
169+
timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval);
170+
}
171+
finally
172+
{
173+
// Restore the current ExecutionContext
174+
if (restoreFlow)
175+
ExecutionContext.RestoreFlow();
176+
}
177+
159178
_timerHandleRef = new GCHandleRef<Timer>(timer);
160179
dispose = false;
161180
}

0 commit comments

Comments
 (0)