Home > Software design >  Calling Task.Delay(50) frequently in a loop. Can this lead to a memory leak?
Calling Task.Delay(50) frequently in a loop. Can this lead to a memory leak?

Time:06-25

In summary. I have ASP.NET Core 6 Rest API project with a BackgroundService that is performing some work every 50 ms. For example:

public class DemoWorker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            // Do work
            Console.WriteLine(DateTimeOffset.Now);
            await Task.Delay(50, stoppingToken);
        }
    }
}

Recently, I noted the following issue reported by the ReSharper Dynamic Program Analysis (DPA) worker.

Small Object Heap: Allocated 8.1 MB (8500792 B), max: 100.2 MB (105041568 B) of type System.Threading.TimerQueueTimer by DemoWorker.ExecuteAsync(CancellationToken)

at System.Threading.Tasks.Task.Delay(uint, CancellationToken) at System.Threading.Tasks.Task.Delay(TimeSpan, CancellationToken) at DemoWorker.ExecuteAsync(CancellationToken) in <SOURCE_CODE_FILE_NAME> at System.Threading.ExecutionContext.RunInternal(ExecutionContext, ContextCallback, Object) at System.Runtime.CompilerServices.AsyncTaskMethodBuilder1 AsyncStateMachineBox1<System.__Canon,StartupHook d__3>.MoveNext(Thread) at System.Threading.Tasks.AwaitTaskContinuation.RunOrScheduleAction(IAsyncStateMachineBox, bool) at System.Threading.Tasks.Task.RunContinuations(Object) at System.Threading.Tasks.Task.TrySetResult() at System.Threading.Tasks.Task DelayPromise.CompleteTimedOut() at System.Threading.TimerQueueTimer.Fire(bool) at System.Threading.TimerQueue.FireNextTimers() at System.Threading.UnmanagedThreadPoolWorkItem.System.Threading.IThreadPoolWorkItem.Execute() at System.Threading.ThreadPoolWorkQueue.Dispatch() at System.Threading.PortableThreadPool WorkerThread.WorkerThreadStart()

I read several articles on this. Most of them are saying that this is not a problem and I don't need to do anything special, or to dispose the task.

But one of the articles says that If I'm creating Task.Delay() calls faster than they're ending, then I will have a memory leak!

So my question is should I worry about this or just ignore it ?

CodePudding user response:

There is a class for this purpose you can use as well.

var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(50));

while (await timer.WaitForNextTickAsync(stoppingToken))
{
    // Do work
    Console.WriteLine(DateTimeOffset.Now);
}

But due to the operating system's architecture, time-related tasks are not 0 reliable.

https://www.c-sharpcorner.com/article/comparison-of-microsoft-windows-tools-for-waiting-time-management/

CodePudding user response:

Suggestion: I might rather use the new PeriodicTimer as it should be memory leak resistant according to this article.

  • Related