0
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.

6
  • 1
    Which callback? Commented Jun 19, 2020 at 6:52
  • Your program ends first, also no Cls will not be garbage collected while the task is alive. Just the fact your are calling this prevents it, among other things... Commented Jun 19, 2020 at 6:53
  • @Gusman the lambda function inside Task.Run Commented Jun 19, 2020 at 6:55
  • 2
    For every method call SignalR creates a new instance of the Hub class. After that method call is over SignalR will Dispose that Hub instance. So if you don't await an async call it will only start it and not wait for completion, then call Dispose on the Hub instance. This Dispose is directly called from the SignalR framework so has nothing to do with GarbageCollection and having references to a Hub. Commented Jun 19, 2020 at 7:37
  • 1
    So the answer to your question is "No it will not be collected by the GC if there is an active reference to the Hub, however it will have been disposed and therefor not 'alive' anymore" Commented Jun 19, 2020 at 7:40

1 Answer 1

2

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
Sign up to request clarification or add additional context in comments.

3 Comments

thank you. I will mark it as accepted answer later on. Because I still don't understand how is the Hub in SignalR works. Seems that if I don't await the Task, the callback inside the Task cannot get reference to the instance as it is garbage collected.
I'm not familiar with SignalR, but maybe it's similar to how Azure Functions work. If you await a Task, the framework knows that you need the app instance to hold and won't terminate. You need to investigate that, I don't know
Thank you @Artemious so clear I will take a try!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.