【问题标题】:Apparent Memory Leak when dispatching from HttpClient continuation从 HttpClient continuation 调度时出现明显的内存泄漏
【发布时间】:2020-12-28 19:21:24
【问题描述】:

问题:在长时间正确使用 HttpClient(作为静态单个实例)后,ConcurrentStack+Node 实例的大小持续增长,导致内存使用量增加。
编辑:这似乎与 SetTextAddText 中调用的调度程序有关。

用例:我正在通过 HTTP 传输轮询本地网络上的设备。我使用 System.Threading.Timer 来控制我的请求频率。轮询计时器的回调是 async void,因此 await 运算符可用于继续控制。默认窗口调度器用于在调用 HttpRequest 后显示文本结果。

娱乐代码:.NET Framework 4.5; WPF ;在 MainWindow 中使用 x:Name="Debug"

创建的单个 TextBlock 的所有标准设置
 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 MB(现在很小,但这是一个长时间运行的应用程序)无法访问的字节由 PinnableBufferCache 分配,大概存储在第 2 代堆中。

我不确定这是内存泄漏还是我不理解的部分内容。为什么我看到这些内存增加,为什么我无法指定 HttpClient 和 WebClient 的本地缓存行为?

【问题讨论】:

  • Debug.Text += text 肯定会使用越来越多的内存,因为TextBlock 的内容会越来越长。这也可能不是添加到TextBlock 的最有效方式,您可以尝试Debug.Inlines.Add(text);

标签: c# .net memory-leaks


【解决方案1】:

我猜AddText,您可以尝试注释掉该方法中的代码,看看内存泄漏是否消失。

【讨论】:

  • 我可以确认 ConcurrentStack+Node 实例在 SetText 和 AddText 正文被注释掉时似乎不再泄漏。但是,Dispatcher 也是将信息从后台线程传播到 UI 线程的事实上的方法……我不知道我该怎么做才能避免它。
猜你喜欢
  • 1970-01-01
  • 2022-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-24
  • 1970-01-01
  • 2013-11-09
相关资源
最近更新 更多