【问题标题】:C# Usercontrol's memory leakC# Usercontrol 的内存泄漏
【发布时间】:2017-11-06 09:01:50
【问题描述】:

我的应用程序中存在严重的内存泄漏。

这是在内存中加载很多东西的表单,它是一个带有 3 个FlowLayoutPanel 的表单。每个面板都有很多我创建的UserControl,它们只是一个带有标签的图片框。让我们调用表单ColorViewer:

每当我打开此表单时,它都会占用近 300-400 MB 的内存,而且似乎不会释放它。

这是内存使用情况的图表:

当我第一次打开ColorViewer 时,它会将所有内容加载到内存中(接近 400mb),然后它就永远不会释放。之后,每次我打开ColorViewer 时,它都会正确处理。

这是我用来加载表单的代码,我猜内存泄漏是在加载 img 时。截至目前,我使用默认的Dispose()

//Loading of one of the three panel in the form,called 3 time when the form is opened:
                colorsViewerPanel.AddColorRange(colours.ConvertAll(x => new ColorBox(x.path_img, x.id,true)));

//Function that loads my UserControl into the panel
      public void AddColorRange(List<ColorBox> cBoxList)
        {
             flowLayoutPanel1.SuspendLayout();

             foreach (var cBox in cBoxList)
                  flowLayoutPanel1.Controls.Add(cBox);

             flowLayoutPanel1.ResumeLayout();
        }

//This is the ColorBox usercontrol's class

public string pathImg{ get; set; }
public int id{ get; set; }
public bool selected{ get; set; }

//This is the constructor for the UserControl
public ColorBox(string pathImage,int idImage,bool sel = true)
  {
        InitializeComponent();
        pathImg = pathImage;
        id = idImage;
        selected = sel;

        //Load img
        if (File.Exists(pathImg))
        {
          Image img;
          using (var bmpTemp = new Bitmap(pathImg))
          {
                img = new Bitmap(pathImg);
          }

          panelColor.BackgroundImage = img;
          panelColor.BackgroundImageLayout = ImageLayout.Stretch;
          labelColor.Text = id;
        }
  }

这正常吗?

【问题讨论】:

  • 内存不会自动释放回系统。它很难分配,因此 CLR 会尽可能长时间地保留它。如果您真的担心内存泄漏,可以使用一些工具来诊断(以及可以找到它们的搜索引擎)。
  • 如果您不共享一行代码,我们如何为您提供帮助?
  • 手动调用GC看是否释放?
  • 您的声明“在那之后,每次我打开 ColorViewer 时它都会被正确处理”是没有意义的。要么正在处理,要么没有。除非你正在做一些相当奇怪的事情并且只是第一次
  • @DonBoitnott 每次加载都是一样的,但是只有当我关闭程序或强制GC收集器通过dotMemory运行时才会清除第一次。我添加了发生内存泄漏的代码。

标签: c# winforms memory-leaks user-controls


【解决方案1】:

我认为你在这里没有处理任何有用的东西:

 Image img;
 using (var bmpTemp = new Bitmap(pathImg))
 {
    img = new Bitmap(pathImg);
 }

您只是在创建 Bitmap 类的实例 (bmpTemp)(稍后将因为 using 语句而被释放),然后将同一类的新实例分配给另一个变量(img,您是有效使用)。无论如何,即使您更正了这一点,它也无法满足您的目的,因为在 PictureBox 中处理您实际显示的图像没有任何意义(这也将导致稍后出现异常)。

正如您在此处所读到的,有必要对 Image 对象调用 Dispose 以有效地消除其在内存中的存在,请记住 Bitmap 是非托管 GDI+ 位图的包装器(并且可能需要特殊需要才能被处理):

Image.Dispose()

也就是说,鉴于您提供的代码并从根本上解决问题,我想我可能会在 ColorBox 控件上实现 IDisposable 接口,以确保在控件被调用时始终调用 Image 实例的 Dispose 方法处置:

Implement IDisposable correctly

在您的具体情况下,我会将 Image/Bitmap 对象视为完全非托管的对象,并且我会在 Dispose 方法的“如果有任何可用的本地资源”部分中释放它,这样,如果有人使用您的控制而不处置它,如果对象有资格进行终结,对终结器的调用无论如何都会发生。像这样的:

 // The bulk of the clean-up code is implemented in Dispose(bool)
 protected virtual void Dispose(bool disposing)
 {
    if (isDisposed) return;

    if (disposing)
    {
        // free managed resources
        managedResource.Dispose();
    }

    // free native resources if there are any.
    if (!(img is null))
    {
       // Our Image.
       img.Dispose();
    }
    isDisposed = true;
 }

【讨论】:

    猜你喜欢
    • 2011-03-19
    • 2016-01-27
    • 2010-11-11
    • 2017-02-18
    • 1970-01-01
    • 2015-11-19
    • 2014-11-01
    • 2020-03-31
    • 2016-03-15
    相关资源
    最近更新 更多