垃圾收集器是否在.NET中的异步调用期间销毁暂时未引用的对象?

想象一下,我将在.NET中进行异步调用,即HttpWebRequest.BeginGetResponse,并且不会在更广泛的范围内引用HttpWebRequest对象。 垃圾收集器会破坏它并导致问题吗?

示例代码:

using System; using System.Net; public class AsyncHttpWebRequest { void Main() { var Request = HttpWebRequest.Create("http://www.contoso.com"); var result = Request.BeginGetResponse(GetResponseCallback, null); } private void GetResponseCallback(IAsyncResult AsyncResult) { // Do Something.. } } 

备用版本(请求作为AsyncState传递):

 using System; using System.Net; public class AsyncHttpWebRequest { void Main() { var Request = HttpWebRequest.Create("http://www.contoso.com"); var result = Request.BeginGetResponse(GetResponseCallback, Request); } private void GetResponseCallback(IAsyncResult AsyncResult) { // Do Something.. } } 

如果任何活动线程包含对它的引用,或者它是静态引用(在两种情况下都直接或间接引用),则该对象被认为是活动的并且不符合垃圾收集条件。

在这两个示例中,异步API都会保留对您的请求的引用(在提供异步IO操作的线程池中),因此在完成之前不会对其进行垃圾回收。

不,垃圾收集器不会给你带来麻烦。

不要以为因为无法访问该对象,垃圾收集器会将其清理干净。

垃圾收集器以许多“根”开始 – 已知可达的对象和引用。 然后,找到从这些根可到达的所有对象,并收集其他所有对象。

每个正在运行的线程(包括处理异步调用的线程)都包含在根列表中。

如果对象没有涉及GC的引用,那么您将无法再获得对它的引用。 所以你不能有一个暂时没有引用它的对象。

(这假设没有像玩游戏的非托管或不安全代码那样偷偷摸摸)

通过异步调用的实现,对象仍然可以正常引用 – 它需要维护所有打开请求的列表,以将传入数据与请求相关联。 最有可能的是,.NET使用全局(或类)变量来存储请求。

在第一个示例代码中,如果您不使用它,为什么要创建Request?

无论如何,如果当前在范围内的任何对象中没有对象存在引用(直接或间接),GC 可以收集它。

因此,在您的第一个示例中,当程序退出时,Main方法仍然在范围内(在另一个线程中),因此在异步调用结束之前不会收集它。 在你的第二个例子中,线程池线程和你的代码都保持对你的对象的引用,所以它显然也不会被收集。