Очевидная утечка памяти при отправке из продолжения HttpClient

#c# #.net #memory-leaks

#c# #.net #утечки памяти

Вопрос:

Проблема: после правильного использования HttpClient (как статического отдельного экземпляра) в течение длительного времени экземпляры ConcurrentStack Node постоянно увеличиваются в размерах, что приводит к увеличению использования памяти.
Редактировать: похоже, это связано с диспетчером, вызываемым в SetText and AddText .

Пример использования: я опрашиваю устройство в своей локальной сети через HTTP-передачу. Я использую System.Многопоточность.Таймер для управления частотой моих запросов. Обратный вызов для таймера опроса является асинхронным void, так что оператор await может использоваться для управления продолжением. Диспетчер окон по умолчанию используется для отображения текстовых результатов после вызова HttpRequest.

Код для восстановления: .NET Framework 4.5; WPF; Все стандартные настройки с одним текстовым блоком, созданным в MainWindow с помощью x:Name=»Debug»

  using System;
 using System.Net;
 using System.Net.Http;
 using System.Threading;
 using System.Threading.Tasks;
 using System.Windows;
    
 namespace LeakIsolator 
 {
     /// <summary>
     /// Interaction logic for MainWindow.xaml
     /// </summary>
     public partial class MainWindow : Window
     {
         static MainWindow()
         {
             WebClient.CachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.NoCacheNoStore);
             HttpClient.DefaultRequestHeaders.CacheControl = new System.Net.Http.Headers.CacheControlHeaderValue()
             {
                 NoStore = true,
                 NoCache = true
             };
         }
    
         public MainWindow()
         {
             InitializeComponent();
    
             Timer = new Timer(Poll, null, Timeout.Infinite, Timeout.Infinite);
             Loaded  = MainWindow_Loaded;
         }
    
         private static HttpClient HttpClient { get; } = new HttpClient();
    
         private static WebClient WebClient { get; } = new WebClient();
    
         private Timer Timer { get; }
    
         private void SetText(string text)
         {
             Dispatcher.Invoke(() => Debug.Text = text);
         }
    
         private void AddText(string text)
         {
             Dispatcher.Invoke(() => Debug.Text  = text);
         }
    
         private async void Poll(object a)
         {
             try
             {
                 SetText("Getting status...");
                 SetText(await GetResponseStringHttpClient("http://10.10.10.87/status"));
             }
             catch (Exception e)
             {
                 SetText($"Exception. {e.Message}");
             }
             finally
             {
                 Start();
             }
         }
    
         private async Task<string> GetResponseStringWebClient(string address)
         {
             return await WebClient.DownloadStringTaskAsync(address);
         }
    
         private async Task<string> GetResponseStringHttpClient(string address)
         {
             using (var response = await HttpClient.GetAsync(address))
             {
                 if (response.IsSuccessStatusCode)
                 {
                     AddText(" Success...");
                     return await response.Content.ReadAsStringAsync();
                 }
                 else
                 {
                     AddText(" Fail.");
                     return null;
                 }
             }
         }
    
         private void Start()
         {
             Timer.Change(1000, Timeout.Infinite);
         }
    
         private void MainWindow_Loaded(object sender, RoutedEventArgs e)
         {
             Start();
         }
     }
 }
 

Используя профилировщик памяти ANTS и запустив приложение в течение 37 минут в последнем тесте, 2.618 МБ (пока мало, но это долго работающее приложение), недоступные для меня байты выделяются PinnableBufferCache, предположительно хранящимся в куче gen 2.

Я не уверен, является ли это утечкой памяти или частью чего-то, чего я не понимаю. Почему я вижу это увеличение объема памяти и почему я не могу диктовать поведение локального кэширования HttpClient и WebClient?

Комментарии:

1. Debug.Text = text определенно будет использовать постоянно увеличивающийся объем памяти по мере увеличения содержимого TextBlock . Это также, вероятно, не самый эффективный способ добавления в a TextBlock , вы можете попробовать Debug.Inlines.Add(text);

Ответ №1:

Я бы предположил AddText , что вы могли бы попробовать прокомментировать код в этом методе и посмотреть, исчезнет ли утечка памяти.

Комментарии:

1. Я могу подтвердить, что экземпляры ConcurrentStack<T> Node<Object> больше не кажутся утечкой, когда setText и addText тела закомментированы. Однако диспетчер также является фактическим методом распространения информации из фонового потока в поток пользовательского интерфейса… Я не знаю, что я могу сделать, чтобы избежать этого.