runtime: Memory leak in SendAsync in HttpClient
In corefx/src/System.Net.Http/src/System/Net/Http/HttpClient.cs:SendAsync there seems to be a memory leak that is triggered when CancellationToken.None is used.
We have created HttpClient once and reuse it:
var httpClientHandler = new HttpClientHandler();
httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
httpClient = new HttpClient(httpClientHandler);
httpClient.Timeout = Timeout.InfiniteTimeSpan;
And are calling like this:
using (var content = PrepareHttpContentJson(input))
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, new Uri(fullUrl, UriKind.RelativeOrAbsolute)))
{
request.Content = content;
using (HttpResponseMessage result = await httpClient.SendAsync(request, CancellationToken.None))
{
// work on result
}
}
PrepareHttpContentJson returns a ByteArrayContent (json content) with ContentType set.
If this code is called repeatably, it leaks every ByteArrayContent created.
Looking to the memory using Diagnostic Tools in Visual Studio, this is what seems to lock the memory:
ByteArrayContent
> Action<Stream>
> HttpWebRequest
> ConnectStream
> ContextAwareResult
> HttpClientHandler+RequestState
> CancellationCallbackInfo
If I replace CancellationToken.None with cts.Token in SendAsync and create var cts = new CancellationTokenSource(); just before the first using, the memory leak stops.
I made this attempt as I checked the source code for HttpClient.cs and noticed some handling of cancellation tokens going on and figured this might be the cause.
Note: This MAY be an interaction issue with Autofac, but I don’t think so. The using code block is resolve by Autofac, but there is only ever 1 instance (registered as single instance) of it (so it wont be disposed between usages).
[EDIT] Add C# syntax highlighting by @karelz
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 35 (14 by maintainers)
I just checked, and the GC fires sparsely, but the memory is still not released. Manually triggering have no difference. However, since I was running 4.6.1 I decided to try newer versions, and it seems the issue was resolved in 4.7.2 since my sample code works without any issues there.
@pabmcdonald check if they run on .NET Framework or .NET Core and what are their dependencies (esp. System.Net.Http nuget). You as a library probably target .NET Standard. Without a confirmed repro there is not much we can do 😦.
@caesar1995 can you please in parallel try the original repro? I wonder if it demonstrates a memory leak on .NET Framework.