Consider the following code snippet:
public void Do()
{
....
Task.Delay(5000).ContinueWith(t => DoSomething());
....
}
Assume that the Do
method finishes execution before the Delay
task is finished and that DoSomething
is not cancelable.
Does the fact that no reference is being maintained to the Task
returned by ContinueWith
method cause some kind of memory leak?
DEFINITION A memory leak is the gradual deterioration of system performance that occurs over time as the result of the fragmentation of a computer's RAM due to poorly designed or programmed applications that fail to free up memory segments when they are no longer needed.
Causes of Memory Leaks and Their Solutions One should not use static views while developing the application, as static views are never destroyed. One should never use the Context as static, because that context will be available through the life of the application, and will not be restricted to the particular activity.
Can you leak (managed) memory by creating new tasks that don't get collected?
Yes.
Does keeping a reference to it (or not) have any effect on it being collected?
Usually* not.
There are 2 types of Tasks: Promise (async) tasks and Delegate (sync) tasks.
Task.Delay
) usually don't get collected as something keeps a reference to it so it can change its state when it needs to (in Task.Delay
it's the internal Timer
that needs to complete the Task
when the delay ends).TaskScheduler
) that's running them.So, if you keep creating tasks you can have a leak whether you're holding a reference or not.
In your specific case, for the first 5 seconds, the internal Timer
references the Promise Task
which in turn references the Delegate Task
(which isn't yet scheduled and doesn't have a thread associated with it). After 5 seconds the Timer
completes the Task.Delay
task which in turn schedules the DoSomething
continuation and so a thread would reference it.
If DoSomething
never completes you have a memory leak (a very small one), if it does complete then you don't.
* You can create tasks (of both kinds) that are only referenced by you and when you don't reference them anymore they can be collected by the GC
. So while this:
static void Main()
{
while (true)
{
Task.Delay(int.MaxValue);
}
}
Will result in a OutOfMemoryException
in a matter of seconds, this can run forever:
static void Main()
{
while (true)
{
new Task(() => Thread.Sleep(int.MaxValue)); // No thread as the task isn't started.
Task.Delay(-1); // No Timer as the delay is infinite.
}
}
The task will be executed on a thread pool thread, once the task is completed the thread will be returned to the pool for use by another task.
Thread pool threads are reclaimed after they've been idle for a period of time (around 45 seconds by default I think).
So the fact that the thread pool holds a reference to it will prevent it from being garbage collected.
The only caveat I guess is that the main application thread has to be running. If you ran the above code in a console app for example the execution would complete before the task, so the task would never run.
In short, no - that code will not cause a memory leak.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With