Si consideri il seguente programma, with all of HttpRequestMessage, and HttpResponseMessage, and HttpClient disposed properly.
Alla fine finisce sempre con circa 50 MB di memoria, dopo la raccolta. Aggiungi uno zero al numero di richieste e la memoria non reclamata raddoppia.HttpClient con conseguente perdita del nodo in mscorlib
class Program
{
static void Main(string[] args)
{
var client = new HttpClient {
BaseAddress = new Uri("http://localhost:5000/")};
var t = Task.Run(async() =>
{
var resps = new List<Task<HttpResponseMessage>>();
var postProcessing = new List<Task>();
for (int i = 0; i < 10000; i++)
{
Console.WriteLine("Firing..");
var req = new HttpRequestMessage(HttpMethod.Get,
"test/delay/5");
var tsk = client.SendAsync(req);
resps.Add(tsk);
postProcessing.Add(tsk.ContinueWith(async ts =>
{
req.Dispose();
var resp = ts.Result;
var content = await resp.Content.ReadAsStringAsync();
resp.Dispose();
Console.WriteLine(content);
}));
}
await Task.WhenAll(resps);
resps.Clear();
Console.WriteLine("All requests done.");
await Task.WhenAll(postProcessing);
postProcessing.Clear();
Console.WriteLine("All postprocessing done.");
});
t.Wait();
Console.Clear();
var t2 = Task.Run(async() =>
{
var resps = new List<Task<HttpResponseMessage>>();
var postProcessing = new List<Task>();
for (int i = 0; i < 10000; i++)
{
Console.WriteLine("Firing..");
var req = new HttpRequestMessage(HttpMethod.Get,
"test/delay/5");
var tsk = client.SendAsync(req);
resps.Add(tsk);
postProcessing.Add(tsk.ContinueWith(async ts =>
{
var resp = ts.Result;
var content = await resp.Content.ReadAsStringAsync();
Console.WriteLine(content);
}));
}
await Task.WhenAll(resps);
resps.Clear();
Console.WriteLine("All requests done.");
await Task.WhenAll(postProcessing);
postProcessing.Clear();
Console.WriteLine("All postprocessing done.");
});
t2.Wait();
Console.Clear();
client.Dispose();
GC.Collect();
Console.WriteLine("Done");
Console.ReadLine();
}
}
Su una rapida indagine con un profiler di memoria, sembra che gli oggetti che occupano la memoria sono tutti di tipo Node<Object>
all'interno mscorlib.
La mia però iniziale era quello, era un po 'dizionario interno o di una pila, dal momento che sono i tipi che utilizza il nodo come una struttura interna, ma io era in grado di girare su tutti i risultati per un generico Node<T>
nel fonte di riferimento poiché questo è in realtà il tipo Node<object>
.
Si tratta di un bug o di qualche tipo di ottimizzazione prevista (non considererei un consumo proporzionale di memoria sempre considerato un'ottimizzazione in alcun modo)? E puramente accademico, qual è il Node<Object>
.
Qualsiasi aiuto nella comprensione di questo sarebbe molto apprezzato. Grazie :)
Aggiornamento: Per estrapolare i risultati per un set di test molto più ampio, l'ho ottimizzato leggermente limitandolo.
Ecco il programma modificato. E ora, it seems to stay consistent at 60-70MB
, per un set di richieste da 1 milione. Sono ancora sconcertato da quello che sono veramente quei Node<object>
e che è autorizzato a mantenere un numero così elevato di oggetti irrecuperabili.
E la conclusione logica delle differenze in questi due risultati mi porta a indovinare, questo potrebbe non essere un problema con HttpClient o WebRequest, piuttosto qualcosa radicato direttamente con async - Dal momento che la vera variante in questi due test è la numero di compiti asincroni incompleti esistenti in un dato momento. Questa è solo una speculazione dell'ispezione rapida.
static void Main(string[] args)
{
Console.WriteLine("Ready to start.");
Console.ReadLine();
var client = new HttpClient { BaseAddress =
new Uri("http://localhost:5000/") };
var t = Task.Run(async() =>
{
var resps = new List<Task<HttpResponseMessage>>();
var postProcessing = new List<Task>();
for (int i = 0; i < 1000000; i++)
{
//Console.WriteLine("Firing..");
var req = new HttpRequestMessage(HttpMethod.Get, "test/delay/5");
var tsk = client.SendAsync(req);
resps.Add(tsk);
var n = i;
postProcessing.Add(tsk.ContinueWith(async ts =>
{
var resp = ts.Result;
var content = await resp.Content.ReadAsStringAsync();
if (n%1000 == 0)
{
Console.WriteLine("Requests processed: " + n);
}
//Console.WriteLine(content);
}));
if (n%20000 == 0)
{
await Task.WhenAll(resps);
resps.Clear();
}
}
await Task.WhenAll(resps);
resps.Clear();
Console.WriteLine("All requests done.");
await Task.WhenAll(postProcessing);
postProcessing.Clear();
Console.WriteLine("All postprocessing done.");
});
t.Wait();
Console.Clear();
client.Dispose();
GC.Collect();
Console.WriteLine("Done");
Console.ReadLine();
}
'HttpClient',' 'HttpRequestMessage' e HttpResponseMessage' siete tutti usa e getta, ma di smaltire solo' HttpClient'. Disponi tutto ciò che ha bisogno di smaltimento (tramite 'using'), quindi controlla di nuovo. (Potrebbe benissimo aver ancora allocato oggetti 'Node <>', ma almeno gli articoli usa e getta non confonderanno il problema.) –
Come ho già menzionato nella prima riga, con tutte le combinazioni di dispose. L'esempio dato non lo smaltisce, ma tutto ha come risultato la stessa perdita. In ogni caso, capisco il tuo punto. Lo modificherà per renderlo chiaro. –
Provare combinazioni diverse in realtà non ha senso. Smaltire * meno * di quanto si suppone non può certamente aiutare a ridurre l'uso della memoria. –