我有一个简单的课程:
public class Runner
{
public void RunAndForget(RunDelegate method)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(Run), method);
}
private void Run(object o)
{
((RunDelegate )o).Invoke();
}
}
如果我这样使用它:
private void RunSomethingASync()
{
Runner runner = new Runner();
runner.FireAndForget(new RunDelegate(Something));
}
这样使用它有危险吗?我的C ++胆量告诉我在RunSomethingASync完成后应该销毁runner对象。我对吗?那么在不同线程上运行的方法会发生什么?
或者可能是另一种方式,跑步者不会被收集?考虑到我可能多次调用RunSomethingASync(),这将是一个问题。
答案 0 :(得分:8)
我的C ++胆量告诉我在RunSomethingASync完成后应该销毁runner对象。我是对的吗?
简而言之,没有。 .NET垃圾收集不是在确定的基础上完成的。一旦对象符合条件进行垃圾收集,一旦它不再生根 - 也就是说,一旦没有更多的引用路径(来自生活对象)就存在了。不能保证任何特定的对象 - 或者实际上任何对象 - 都会被垃圾收集,尽管它很可能。
但是,在您的情况下,您的对象甚至不符合条件。虽然对象超出了代码中的范围(因此看起来似乎没有引用),但委托确实包含对其拥有实例的引用(假设它们指向实例方法)。在调用Run
之前,对您的对象的引用将存在,因为ThreadPool
在此之前持有对该委托的引用,并且该委托具有对Runner
的引用。
所以,回答你的问题,你所做的事情没有危险。因为委托引用了实例,所以在操作完成之前,不能也不会收集对象。完成后,您的对象将符合条件。
答案 1 :(得分:5)
在对象不再被root化之前,它不会被垃圾收集 - 也就是说,直到对它的所有可到达引用都被删除。这有一个例外,如果两个对象彼此保持引用而没有其他任何东西保存对这些对象的引用,那么这两个对象可用于垃圾收集。像你这样运行异步方法会保存对象的引用,并且不会在调用期间处理。
以下注释的注释:在方法上调用Dispose()不会强制该对象上的垃圾收集。
由于我们在谈论垃圾收集,这里是GC.Collect函数的链接: http://msdn.microsoft.com/en-us/library/xe0c2357.aspx
和GC类本身:
http://msdn.microsoft.com/en-us/library/a0fwz4wc(v=VS.100).aspx
编辑:请参阅Adam关于委托和对象引用的答案。
答案 2 :(得分:0)
不,无法收集运行代码的对象,因为对对象有多个引用(例如“this”是对象的引用)。