【发布时间】:2012-12-28 19:57:56
【问题描述】:
我正在开发 WebCrawler implementation,但在 ASP.NET Web API 的 HttpClient 中遇到了奇怪的内存泄漏。
所以精简版在这里:
[更新 2]
我发现了问题,不是 HttpClient 泄漏了。看我的回答。
[更新 1]
我添加了 dispose 但没有任何效果:
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();
}
包含链接的文件可用here。
这会导致内存不断上升。内存分析显示 AsyncCallback 可能持有许多字节。我之前做过很多内存泄漏分析,但这一次似乎是在 HttpClient 级别。
我使用的是 C# 4.0,所以这里没有 async/await,所以只使用了 TPL 4.0。
上面的代码有效,但没有优化,有时会发脾气,但足以重现效果。关键是我找不到任何可能导致内存泄漏的点。
【问题讨论】:
-
这将每秒至少启动一个请求。也许您每秒处理
-
@usr 我只是限制等待的请求数量,并每秒检查一次。如果我不这样做,这将创建 1000 多个任务。
-
在检查并等待之后,您仍然可以开始另一个。你总是开始一个。
-
我已经尝试过了,我确实看到一开始有增加。由于服务器未响应而导致大约 50 次异常后,内存负载确实从 397MB 下降到 69MB 并保持在那里。似乎您有许多尚未返回的并发请求待处理。超时导致挂起的任务被取消后一切恢复正常。
-
@Aliostad 这无济于事,但它可能会稍微减少代码......除非您使用 HttpCompletionOption.ResponseHeadersRead,否则 LoadIntoBufferAsync 是多余的。
标签: c# memory-leaks asp.net-web-api dotnet-httpclient