Garbage Collector distrugge oggetti temporaneamente non referenziati durante le chiamate asincrone in .NET?

StackOverflow https://stackoverflow.com/questions/421547

Domanda

Immagina che farò una chiamata asincrona in .NET, ovvero HttpWebRequest.BeginGetResponse, e l'oggetto HttpWebRequest non è referenziato in un ambito più ampio. Garbage Collector lo distruggerà e causerà problemi?

Codice di esempio:

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..
    }
}

Versione alternativa (con la richiesta passata come 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..
    }
}
È stato utile?

Soluzione

Un oggetto è considerato vivo e non idoneo per la garbage collection se un thread attivo contiene un riferimento ad esso o se è referenziato staticamente (direttamente o indirettamente in entrambi i casi).

In entrambi gli esempi l'API asincrona mantiene un riferimento alla tua richiesta (all'interno del pool di thread in cui sono archiviate le operazioni di I / O asincrone) e quindi non verrà spazzata via fino al completamento.

Altri suggerimenti

No, il Garbage Collector non ti causerà problemi.

Non dare per scontato che, poiché tu non hai accesso all'oggetto, il garbage collector lo ripulirà.

Il Garbage Collector inizia con un numero di "radici" - oggetti e riferimenti noti raggiungibili. Quindi, vengono trovati tutti gli oggetti raggiungibili da quelle radici e tutto il resto viene raccolto.

Ogni thread in esecuzione - inclusi i thread che elaborano le chiamate Async sono inclusi nell'elenco delle radici.

Se un oggetto non ha riferimenti per quanto riguarda il GC, non è più possibile ottenere un riferimento ad esso. Quindi non puoi avere un oggetto che temporaneamente non abbia un riferimento ad esso.

(Questo non presuppone nulla di subdolo come un codice non gestito o non sicuro nei giochi)

L'oggetto rimane referenziato bene dall'implementazione di chiamate asincrone - che deve mantenere un elenco di tutte le richieste aperte, per correlare i dati in arrivo alle richieste. Molto probabilmente, .NET utilizza una variabile globale (o di classe) per memorizzare le richieste.

Nel primo codice di esempio, perché crei Richiesta, se non la usi?

In ogni caso, se non esiste alcun riferimento (diretto o indiretto) a un oggetto proveniente da uno qualsiasi degli oggetti attualmente nell'ambito, il GC può raccoglierlo.

Quindi nel tuo primo esempio quando il programma esce dal metodo principale Request è ancora nell'ambito (in un altro thread), quindi non verrà raccolto fino al termine della chiamata asincrona. Nel tuo secondo esempio, entrambi, il thread del pool di thread e il codice mantengono un riferimento al tuo oggetto, quindi ovviamente non verrà raccolto anche.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top