2 votes

Fuite de mémoire dans httpClient.GetAsync C# .NET 4.8

J'ai un problème de fuite de mémoire lorsque j'utilise httpClient.GetAsync .
Dans le gestionnaire des tâches, les processus restent avec une forte consommation de mémoire qui n'est pas libérée.

Voici mon code :

HttpClient httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromMinutes(2);

try
{
    using (var response = await httpClient.GetAsync(fullURL))
    {
        if (!response.IsSuccessStatusCode)
        {
            Logger.Default.Error($"error code {(int)response.StatusCode} - {response.StatusCode}");
            return null;
        }
        using (MemoryStream memStream = new MemoryStream())
        {
            await response.Content.CopyToAsync(memStream);
            Logger.Default.Debug($"finished reading response, sized {Math.Round(memStream.Length / Math.Pow(1024, 2), 2)} MB");
        }
    }
}
catch (TaskCanceledException ex)
{
    Logger.Default.Error($"Request timed out. {ex.Message}\n{ex.StackTrace}");
    return null;
}

Cependant, lorsque j'utilise httpClient.GetStreamAsync à la place, et changer :

await response.CopyToAsync(memStream);

A :

await response.Content.CopyToAsync(memStream);

La mémoire se libère au bout de quelques secondes. Mais je préfère utiliser GetAsync puisqu'il me fournit des informations sur le code d'état, qui GetStreamAsync ne le fait pas.

J'ai déjà essayé d'appeler le Garbage collector ( GC.Collect(2) ) après que l'objet ait été éliminé, mais cela n'a pas aidé.

Qu'est-ce que je fais de mal ?

0voto

cklimowski Points 370

HTTPClient m'a déjà posé des problèmes de ce type. J'ai trouvé cet article très utile :

https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/

En fait, même s'il implémente IDisposable, vous pouvez l'instancier pendant toute la durée de vie de l'application en tant que singleton. Cela permet à l'application de n'utiliser que la connexion HTTPClient, et n'entraînera pas de problèmes si la connexion n'est pas éliminée correctement.

Si vous l'utilisez dans un bloc d'utilisation, Windows maintiendra une connexion dans cet état pendant 240 secondes. Il est défini par :

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpTimedWaitDelay]

Essayez ceci :

using System;
using System.Net.Http;

namespace ConsoleApplication
{
    public class Program
    {
        private static HttpClient Client = new HttpClient();
        public static async Task Main(string[] args) 
        {
            Console.WriteLine("Starting connections");
            for(int i = 0; i<10; i++)
            {
                var result = await Client.GetAsync("http://aspnetmonsters.com");
                Console.WriteLine(result.StatusCode);
            }
            Console.WriteLine("Connections done");
            Console.ReadLine();
        }
    }
}

Si vous implémentez IDisposable par la syntaxe de l'instruction using, la connexion reste en fait ouverte après la fin du bloc using. Ainsi, lorsque votre application rencontre un autre bloc using de HTTPClient, la connexion existante n'est pas encore fermée. Cela peut entraîner toutes sortes d'erreurs, le plus souvent :

Il y a une limite à la vitesse à laquelle Windows peut ouvrir de nouveaux sockets, donc si vous épuisez le pool de connexion, vous risquez de voir apparaître une erreur du genre :

Unable to connect to the remote server
System.Net.Sockets.SocketException: Only one usage of each socket address (protocol/network address/port) is normally permitted.

D'autres personnes sur Internet ont trouvé de meilleures façons de procéder. Je n'ai pas personnellement d'expérience dans ce domaine, mais voici quelques liens qui méritent d'être consultés. Ils décrivent des façons d'utiliser IHTTPClientFactory et d'autres façons de le faire sans établir un Singleton HTTPClient :

https://josef.codes/you-are-probably-still-using-httpclient-wrong-and-it-is-destabilizing-your-software/

https://www.stevejgordon.co.uk/httpclient-creation-and-disposal-internals-should-i-dispose-of-httpclient

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X