繁体   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