Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does not having a reference to a Task cause memory leaks?

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?

like image 874
Omri Btian Avatar asked Mar 26 '15 06:03

Omri Btian


People also ask

What is the main cause of memory leaks?

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.

What should be avoided to prevent memory leaks?

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.


2 Answers

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.

  • Promise tasks (like 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).
  • Delegate tasks (as RagtimeWilly explained) are referenced by the thread (and 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.
    }
}
like image 125
i3arnon Avatar answered Sep 29 '22 22:09

i3arnon


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.

like image 32
RagtimeWilly Avatar answered Sep 29 '22 21:09

RagtimeWilly