簡體   English   中英

如果任務的回調獲取對實例本身的引用,實例是否會被垃圾收集?

[英]Will an instance be garbage collected if a Task's callback get reference to the instance itself?

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();
    }
}

請考慮上面的代碼,如果它首先有意義,請忽略它。 在上述情況下,我沒有將Cls的實例存儲到任何變量中,似乎沒有任何東西引用該實例,它將是 GC。 但是,在Func側有一個Task.Run() Task的回調 function 引用了實例的Obj屬性。 在這種情況下,我還能被 GC 收集嗎?


我問這個問題是因為在 SignalR 的微軟文檔中它說

在調用依賴於集線器保持活動狀態的異步方法時使用等待。

我不明白,只要Clients.All.SendAsync中的某些內容引用Hub本身, Hub為什么不會仍然存在......

謝謝。

不,它不會被垃圾收集,因為您在Task.Run()中引用了this (即使您在調用Thead.Sleep()之前引用this )。

但是,如果您在 Azure 函數中運行此代碼,例如,框架可能會終止您的應用程序實例,並且回調中的代碼將永遠不會運行(不是因為被垃圾收集)。

順便說一句,您可以通過調用執行垃圾收集的GC.Collect()手動檢查它是否被垃圾收集。

您可以使用此代碼對其進行測試(例如,在 C# Interactive 中運行它)

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);

如果您在 Task.Run(..) 中沒有引用this.Obj ,那么它將 output 這個:

Cls constructor
before Task.Delay
after Task.Delay
GC.Collect()
after GC.Collect()
before Task.Delay
!!! Cls deconstructor
after Task.Delay

但如果你這樣做,它將 output 這個:

Cls constructor
before Task.Delay
after Task.Delay
GC.Collect()
after GC.Collect()
before Task.Delay
after Task.Delay

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM