Reputation: 1851
public class Cls
{
public object Obj { get; set; }
public async void Func()
{
Task.Run(() =>
{
Thread.Sleep(999999999);
this.Obj = new { };
});
}
}
public class Program
{
public static void Main(string[] args)
{
new Cls().Func();
}
}
Please consider the above codes and neglect if it makes sense first. In the above case, I did not store instance of Cls
into any variable, seems that nothing is referencing that instance and it would be GC. However, there is a Task.Run()
in side Func
. The callback function of the Task
make a reference to the instance's Obj
property. May I will it still be collected by GC in such case?
I am asking this question because in Microsoft doc of SignalR it stated
Use await when calling asynchronous methods that depend on the hub staying alive.
I don't understand how come the Hub
will not still alive as long as something inside Clients.All.SendAsync
is referencing to the Hub
itself...
Thanks.
Upvotes: 0
Views: 304
Reputation: 2075
No, it will not be garbage collected, because you have reference to this
in Task.Run()
(even if you reference this
before call to Thead.Sleep()
).
However, if you're running this code in Azure Functions, for example, the framework may terminate your app instance and the code in callback will not ever run (not because of being garbage collected).
By the way, you can manually check if it is garbage collected by calling GC.Collect()
, which performs garbage collection.
You can use this code to test it (run it in C# Interactive, for example)
static async Task Main(string[] args)
{
static void CreateObjectAndCallFunc()
{
var clsInstance = new Cls();
clsInstance.Func();
}
CreateObjectAndCallFunc();
Console.WriteLine($"before Task.Delay");
await Task.Delay(10);
Console.WriteLine($"after Task.Delay");
Console.WriteLine($"GC.Collect()");
GC.Collect();
Console.WriteLine($"after GC.Collect()");
Console.WriteLine($"before Task.Delay");
await Task.Delay(10);
Console.WriteLine($"after Task.Delay");
}
public class Cls
{
public Cls() { Console.WriteLine("Cls constructor"); }
~Cls() { Console.WriteLine("!!! Cls deconstructor"); }
public object Obj { get; set; }
public void Func()
{
Task.Run(() =>
{
System.Threading.Thread.Sleep(99999);
this.Obj = new object();
});
}
}
await Main(null);
If you don't reference this.Obj
in Task.Run(..), then it will output this:
Cls constructor
before Task.Delay
after Task.Delay
GC.Collect()
after GC.Collect()
before Task.Delay
!!! Cls deconstructor
after Task.Delay
but if you do, it will output this:
Cls constructor
before Task.Delay
after Task.Delay
GC.Collect()
after GC.Collect()
before Task.Delay
after Task.Delay
Upvotes: 2