HttpClient rampant entraîne une fuite de mémoire
Je suis en train de travailler sur un WebCrawler la mise en œuvre mais suis confronté à un étrange fuite de mémoire dans ASP.NET Web API HttpClient.
De sorte que la coupe vers le bas la version est ici:
[Mise à JOUR 2]
J'ai trouvé le problème et il n'est pas HttpClient qui fuit. Voir ma réponse.
[JOUR 1]
J'ai ajouté en disposer avec aucun effet:
static void Main(string[] args)
{
int waiting = 0;
const int MaxWaiting = 100;
var httpClient = new HttpClient();
foreach (var link in File.ReadAllLines("links.txt"))
{
while (waiting>=MaxWaiting)
{
Thread.Sleep(1000);
Console.WriteLine("Waiting ...");
}
httpClient.GetAsync(link)
.ContinueWith(t =>
{
try
{
var httpResponseMessage = t.Result;
if (httpResponseMessage.IsSuccessStatusCode)
httpResponseMessage.Content.LoadIntoBufferAsync()
.ContinueWith(t2=>
{
if(t2.IsFaulted)
{
httpResponseMessage.Dispose();
Console.ForegroundColor = ConsoleColor.Magenta;
Console.WriteLine(t2.Exception);
}
else
{
httpResponseMessage.Content.
ReadAsStringAsync()
.ContinueWith(t3 =>
{
Interlocked.Decrement(ref waiting);
try
{
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(httpResponseMessage.RequestMessage.RequestUri);
string s =
t3.Result;
}
catch (Exception ex3)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine(ex3);
}
httpResponseMessage.Dispose();
});
}
}
);
}
catch(Exception e)
{
Interlocked.Decrement(ref waiting);
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(e);
}
}
);
Interlocked.Increment(ref waiting);
}
Console.Read();
}
Le fichier contenant les liens est disponible ici.
Il en résulte une hausse constante de la mémoire. Mémoire analyse indique le nombre d'octets tenu, éventuellement, par la AsyncCallback. J'ai fait beaucoup de fuite de mémoire analyse avant mais celui-ci semble être à la HttpClient.
Je suis à l'aide de C# 4.0, donc pas async/await ici, donc seulement TPL 4.0 est utilisé.
Le code ci-dessus fonctionne, mais n'est pas optimisé, et parfois jette crise est encore assez pour reproduire l'effet. Point est que je ne peut pas trouver n'importe quel point qui pourrait provoquer mémoire fuite.
source d'informationauteur Aliostad
Vous devez vous connecter pour publier un commentaire.
OK, je suis arrivé au bas de cette. Grâce à @Tugberk, @Darrel et @youssef pour passer du temps sur ce.
Fondamentalement le problème initial, c'est frai de trop nombreuses tâches. Cela a commencé à prendre son péage j'ai donc dû couper de retour sur, et certains d'état pour s'assurer que le nombre de tâches simultanées sont limitées. C'est un grand défi pour l'écriture des processus qui ont à utiliser TPL pour planifier les tâches. Nous pouvons contrôler les threads du pool de threads, mais nous avons aussi besoin de contrôler les tâches qui nous sont création de, donc pas de niveau de
async/await
aidera.J'ai réussi à reproduire la fuite seulement une couple de fois avec ce code, d'autres fois après une croissance de il serait tout simplement abandonner subitement. Je sais qu'il y a une réorganisation de l'GC en 4.5 donc peut-être que le problème ici est que la GC n'a pas un coup de pied assez bien que j'ai été à la recherche à la perf des compteurs sur GC génération 0, 1 et 2 collections.
Donc l'emporter ici est que la ré-utilisation de
HttpClient
ne provoque PAS de fuite de mémoire.Je ne suis pas bon à la définition des problèmes de mémoire, mais j'ai essayé avec le code suivant. C'est dans .NET 4.5 et utilise async/await fonction de C#, trop. Il semble garder l'utilisation de la mémoire autour de 10 - 15 MO pour l'ensemble du processus (vous ne savez pas si vous voyez ce une meilleure utilisation de la mémoire). Mais si vous regardez # Collections de la génération 0# Gen 1 Collections et # Gen 2 Collections perf compteurs, ils sont assez haut avec le code ci-dessous.
Si vous supprimez le
GC.Collect
appels ci-dessous, il va-et-vient entre 30 MO à 50 mo pour l'ensemble du processus. La partie intéressante est que lorsque j'exécute ton code sur mon 4 core de la machine, je ne vois pas anormal de l'utilisation de la mémoire par le processus. J'ai .NET 4.5 est installé sur ma machine et si vous ne le faites pas, le problème peut être lié au CLR internes .NET 4.0 et je suis sûr que TPL, s'est beaucoup améliorée .NET 4.5 sur la base de l'utilisation des ressources.Un récent rapporté "Fuite de Mémoire" dans notre environnement d'assurance qualité nous a appris ceci:
Envisager la Pile TCP
Ne présumez pas que la Pile TCP peut faire ce qui est demandé dans le temps ", estime approprié de l'application". On peut bien sûr spin off de Tâches à volonté et nous aimons tout simplement asych, mais....
Regarder la Pile TCP
Exécuter la commande NETSTAT quand vous pensez que vous avez une fuite de mémoire. Si vous voyez résiduelle des séances ou à moitié cuit, états-unis, vous voudrez peut-être repenser votre conception ainsi que les lignes de HTTPClient de réutilisation et de limiter le montant de l'simultanées de travail en rotation. Vous aurez également besoin d'envisager l'utilisation de l'Équilibrage de la Charge sur plusieurs machines.
À moitié cuit séances dans NETSTAT avec Fin-Attend 1 ou 2 de Temps et Attend ou même de la TVD-ATTENDRE 1 et 2. Même "Établi", les séances peuvent être pratiquement mort peu d'attente pour le temps d'attente pour le feu.
De la Pile .NET sont les plus susceptibles de ne pas rompre
La surcharge de la pile met la machine à dormir. La récupération prend du temps et 99% du temps à la pile de se rétablir. Rappelez-vous également que .NET ne sera pas libérer les ressources avant leur temps et qu'aucun utilisateur a le contrôle total de la GC.
Si vous tuez l'application et il faut 5 minutes pour NETSTAT pour s'installer, c'est un très bon signe que le système est débordé. C'est aussi un bon spectacle de la façon dont la pile est indépendant de l'application.
La valeur par défaut
HttpClient
fuites lorsque vous l'utilisez comme un objet éphémère et de créer de nouvelles HttpClients par demande.Ici est une reproduction de ce comportement.
Comme une solution de contournement, j'ai été en mesure de continuer à utiliser HttpClient comme un objet éphémère à l'aide de la suite de package Nuget au lieu de l'intégré dans
System.Net.Http
assemblée:https://www.nuget.org/packages/HttpClient
Pas sûr de ce que l'origine de ce package est, cependant, dès que j'ai référencé la fuite de mémoire a disparu. Assurez-vous que vous supprimez la référence à l'intégré .NET
System.Net.Http
bibliothèque et utiliser le package Nuget à la place.