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

C# 垃圾收集器是否在.NET异步调用期间临时销毁未引用的对象?,c#,.net,asynchronous,garbage-collection,C#,.net,Asynchronous,Garbage Collection,假设我将在.NET中进行一个异步调用,即HttpWebRequest.BeginGetResponse,HttpWebRequest对象没有在更广的范围内引用。垃圾收集器会破坏它并导致问题吗 示例代码: using System; using System.Net; public class AsyncHttpWebRequest { void Main() { var Request = HttpWebRequest.Create("http://www.co

假设我将在.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..
    }
}
备用版本(请求以异步状态传递):


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


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

在第一个示例代码中,如果不使用请求,为什么要创建请求

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

因此,在第一个示例中,当程序退出时,Main方法请求仍在作用域中(在另一个线程中),因此在异步调用结束之前,它不会被收集。
在第二个示例中,线程池线程和代码都保留了对对象的引用,因此它显然也不会被收集。

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

不,垃圾收集器不会给您带来问题

不要假设因为您没有访问该对象的权限,垃圾收集器将对其进行清理

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


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

如果一个对象在GC方面没有引用,那么您就无法再获取对它的引用。所以你不能有一个暂时没有引用的对象


(这假设没有什么比玩游戏的非托管或不安全代码更狡猾的了)

是的,我看到了。固定的。我被代码的颜色弄糊涂了;)在我提供的第二个示例中,有一段时间间隔我看不到对请求对象的任何引用。这就是我所说的“暂时不被引用”的意思。真正发生的是引用隐藏在某个.NET对象中。我的观点是GC不关心你能看到什么,只关心任何人能看到什么。如果有任何东西可以看到它或能够看到它(我认为它们是一样的),它就不会收集它。顺便说一句,这就是为什么你总是要调用End[Blah]Async()-来告诉异步调用程序扔掉为此目的保留的引用的原因吗?@Tom,我认为这与清除任何不受GC约束的非托管资源有关。这是一个总的指导原则,尽管我发现有些情况下,火灾和遗忘似乎不会造成任何泄漏。
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..
    }
}