简体   繁体   English

httpClient.GetAsync 中的 Memory 泄漏 C# .NET 4.8

[英]Memory leak in httpClient.GetAsync C# .NET 4.8

I have a memory leak issue when using httpClient.GetAsync .使用httpClient.GetAsync时,我遇到了 memory 泄漏问题。
In the task manager, the processes stay with a high memory consumption that doesn't get freed.在任务管理器中,进程保持较高的 memory 消耗,不会被释放。

This is my 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;
}

However, when I use httpClient.GetStreamAsync instead, and change:但是,当我改用httpClient.GetStreamAsync并更改时:

await response.CopyToAsync(memStream);

To:至:

await response.Content.CopyToAsync(memStream);

The memory does get released after a few seconds. memory 确实会在几秒钟后释放。 But I rather use GetAsync since it provides me information about the status code, which GetStreamAsync doesn't.但我更喜欢使用GetAsync ,因为它为我提供了有关状态代码的信息,而GetStreamAsync没有。

I've already tried calling the Garbage collector ( GC.Collect(2) ) after the object got disposed, but it didn't help.在 object 被处理后,我已经尝试调用垃圾收集器( GC.Collect(2) ),但它没有帮助。

What am I doing wrong?我究竟做错了什么?

HTTPClient has given me issues like this before. HTTPClient 以前给过我这样的问题。 I found this article very helpful:我发现这篇文章很有帮助:

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

Basically, even though it implements IDisposable, you can instead instantiate it for the lifetime of the application as a singleton.基本上,即使它实现了 IDisposable,您也可以在应用程序的整个生命周期内将其实例化为 singleton。 This allows the app to only use that HTTPClient connection, and won't lead to issues where the connection is not disposed properly.这允许应用程序仅使用该 HTTPClient 连接,并且不会导致连接未正确处理的问题。

If you use it within a using block, Windows will hold a connection in this state for 240 seconds.如果您在 using 块中使用它,Windows 将在此 state 中保持连接 240 秒。 It is set by:它由以下人员设置:

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

Try this out:试试这个:

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();
        }
    }
}

If you implement IDisposable by the using statement syntax, the connection actually stays open after the end of the using block.如果您通过 using 语句语法实现 IDisposable,则连接实际上在 using 块结束后保持打开状态。 Then, when your application comes across another using block of HTTPClient, the previously existing once is not closed yet.然后,当您的应用程序遇到另一个使用 HTTPClient 块时,先前存在的一次还没有关闭。 This can lead to all sorts of errors, most commonly:这可能会导致各种错误,最常见的是:

There is a limit to how quickly Windows can open new sockets so if you exhaust the connection pool then you're likely to see an error like: Windows 打开新 sockets 的速度是有限制的,所以如果你用尽了连接池,那么你可能会看到如下错误:

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.

Some others on the internet have found better ways to do this, I don't personally have experience with them, but here are some links worth checking out.互联网上的其他一些人已经找到了更好的方法来做到这一点,我个人没有经验,但这里有一些值得一试的链接。 These describe ways to use IHTTPClientFactory and other ways to do this without establishing an HTTPClient Singleton:这些描述了在不建立 HTTPClient Singleton 的情况下使用 IHTTPClientFactory 的方法和其他方法:

https://josef.codes/you-are-probably-still-using-httpclient-wrong-and-it-is-destabilizing-your-software/ 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 https://www.stevejgordon.co.uk/httpclient-creation-and-disposal-internals-should-i-dispose-of-httpclient

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM