I have a Windows
form application that i want on each OnLoad
to start an async Task
that gets disposed on the next OnLoad
.
After running with the Profiler
i see that the object count gets bigger and bigger after each OnLoad
.
I know that the GC
does not free the memory right when you call Dispose
nor when you set to null
.Should i override the finalizer ?
I have also considered a CancellationTokenSource
but i
Form
public class MyForm:Form
{
private Task task;
protected override OnLoad()
{
if(this.task!=null)
{
this.task.Dispose();
this.task=null;
}
this.task=Task.Run(()=>....);
}
}
With Token
public class MyForm:Form
{
private Task task;
private CancellationTokenSource=new CancellationTokenSource();
protected override OnLoad()
{
if(this.task!=null)
{
src.Cancel();
}
try
{
this.task=Task.Run(()=>....,src.Token);
}catch(TaskCancelledException ex)
{
return;
}
}
}
The problem with CancellationTokenSource
is that as you can see i would call Cancel
on a previous Task
(At the second OnLoad
call i would dispose the first Task
) and i do not know if that would get handled in the Try-Catch
block.
What would be a good method to dispose the Task
object as soon as possible ? This Form
would reload continously on a computer at timed intervals, and i do not want to dispose it, just the Task
You do not have to dispose of the tasks in your situation. It only implements IDisposable because it may allocate a WaitHandle (which is disposable):
Internally, Task may allocate a WaitHandle which can be used to wait on the Task to complete. WaitHandle is IDisposable because it holds onto a SafeWaitHandle internally, which is IDisposable. SafeWaitHandle wraps a native handle resource: if the SafeWaitHandle isn’t disposed, eventually its finalizer will get around to cleaning up the wrapped handle, but in the meantime its resources won’t be cleaned up and pressure will be put on the system. By implementing IDisposable on Task, then, we enable developers concerned about aggressively cleaning up these resources to do so in a timely manner.
Now, Microsoft did realize this can create confusion so they made some changes and created some guidance:
We’ve made it much less likely that the Task’s WaitHandle will be allocated at all. We’ve re-implemented WaitAll and WaitAny so that they don’t rely on a Task’s WaitHandle, and we’ve avoided using it internally for any of the new Task or async/await-related functionality introduced in .NET 4.5. Thus, the only way the WaitHandle will be allocated is if you explicitly ask for the Task’s IAsyncResult.AsyncWaitHandle, and that should be quite rare. This means that except in such very infrequent circumstances, disposing of a Task is completely unnecessary.
and
We’ve made Tasks usable even after they’ve been disposed. You can now use all of the public members of Task even after its disposal, and they’ll behave just as they did before disposal. The only member you can’t use is IAsyncResult.AsyncWaitHandle, since that’s what actually gets disposed when you dispose of a Task instance; that property will continue to throw an ObjectDisposedException if you try to use it after the Task has been disposed. This means you should feel freely comfortable caching completed Tasks, knowing that they’re observationally pure. Additionally, moving forward, IAsyncResult usage should drop significantly now that we have async/await and the Task-based Async Pattern, and even for continued usage of IAsyncResult, usage of its AsyncWaitHandle is quite rare.
The basic advice however is:
“No. Don’t bother disposing of your tasks.” It’s often difficult to find a good place to do so, there’s almost never a reason to do so, and depending on your reference assemblies, you might not even be able to do so.
(source)