【问题标题】:Memory Leak caused by System.Drawing.Internal.GPStreamSystem.Drawing.Internal.GPStream 导致的内存泄漏
【发布时间】:2014-04-19 17:54:21
【问题描述】:

每次打开和关闭某个表单时,我的应用程序的大小都会不断增长。我使用 dotTrace 并提出了一个不断增长的 System.Drawing.Internal.GPStream 类型的对象列表,这些对象不断创建字节数组,而不是每次都处理它们。我做了一些研究,发现.net 不支持任何关闭此类内存流的方法。以下

foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())
{
    if (t.IsClass && t.BaseType.Name.ToLower() == "form") 
    {
        //Assembly ass = Assembly.GetExecutingAssembly();
        object obj = null;
        obj = Activator.CreateInstance(t);
        Form f = new Form();
        f = (Form)obj;
        if ((string)f.Tag != "DNI") // Do Not Import
        {
            DataRow dr = Formsdt.NewRow();
            dr["Name"] = f.Name;
            dr["Text"] = f.Text;
            dr["Tag"] = f.Tag;
            Formsdt.Rows.Add(dr);
        }
    }
}

此代码的目的是遍历所有表单并检索控件,以便为用户设置访问权限,根据需要以编程方式激活和停用控件。

感谢任何见解。 注意 虽然(我正在打开和关闭表单) ==> 内存分配不断增加

【问题讨论】:

  • 不要在 .NET 中查找泄漏,而是检查表单中是否存在您正在加载但未处理的任何 GDI 对象(例如位图),或者您正在创建的流而不关闭它们。查看this类似问题
  • 没有明确创建流或位图。但是,我确实这样做了,内存泄漏确实是由与内存泄漏一致的 byte[] 组成的。
  • 我可以补充一点,我绝对确定这是一个内存 IO 流驱动的问题。
  • 通常用于加载位图的内存流,在 System.Drawing 中定义。您确实需要检查表格,12 年后您不太可能是第一个注意到 System.Drawing 泄漏的人。表单是否使用位图或其他 GDI 对象?
  • 也许可以试试 Resharper,找到没有发布的资源。

标签: c# winforms memory-leaks idisposable system.drawing


【解决方案1】:

有些东西没有妥善处理。您是否有警告说 X 类是 iDisposable 并且您没有处理它?研究使用“使用”块。

看到这个:

"FileStream 涉及非托管资源,实际上可能是 调用 Dispose 后立即释放。另一个是 MemoryStream 手,将托管字节数组存储在其 _buffer 变量中,即 未在处置时释放。事实上,_buffer 甚至没有被清空 MemoryStream 的 Dispose 方法,这是一个 SHAMEFUL BUG IMO,因为 清空引用可以使内存在 处置时间。相反,一个挥之不去(但已处理)的 MemoryStream 引用仍然保留在内存中。因此,一旦你处理它,你 如果它仍在范围内,也应该将其设为空。” – Triynko 2010 年 10 月 25 日在 20:46

Is a memory leak created if a MemoryStream in .NET is not closed?

【讨论】:

  • 例如,从发布的代码中,操作会执行 Form f = new Form(); (他甚至不应该这样做),但不会被处理。他也做了f = (Form)obj,也从未处理过该对象。 (你真的应该只是在做using(Form f = (Form)obj)
  • 我已经尝试了 using 块,但仍然没有成功。无论如何,我有理由相信是激活器导致了这个问题,但还不能确定。我所知道的是 System.Drawing.Internal.GPStream 是我此时出现问题的原因。所有解决内存泄漏问题的尝试都失败了。我确实使用了@ScottChamberlain 建议的代码,它没有任何改变,因为表单的类型是 Idisposable 并且由 GC 释放,这与内存流不同。
  • 所有Stream派生对象都是一次性的。 MemoryStream 就是这样一个类。你在谈论一个不同的流对象
  • @Cogent 问题不在于您显示的代码,问题在于您创建的 Form 对象之一的代码。我只是用你的代码作为你需要做的一个例子,你需要仔细检查每个表单并找到一个没有正确处理它自己的对象。
  • @Cogent 如果您创建的任何可处置的东西足够大,您应该在分配它时看到内存飙升。也许加载一个非常大的,看看当你关闭表单时它是否会掉下来?如果您没有收到信息性警告,应该可以帮助您确定调试。
【解决方案2】:

在循环中创建表单会导致问题,这取决于它的构造函数中的代码,它可以触发会阻塞消息循环的事件。只是为了检查,尝试在循环中添加一个 application.doevents 并观察内存是否被释放。

也许您需要重构您的类以确定对表单外属性的访问。比如:

Class MyObject
Public my_form as Form
Public Tag as string
end class

因此您不需要实例化表单。

问候,

马里亚诺C.

【讨论】:

    猜你喜欢
    • 2015-07-06
    • 2014-06-07
    • 2013-11-20
    • 2011-10-28
    • 2016-01-18
    • 2012-12-13
    • 1970-01-01
    • 2011-01-08
    • 2011-02-01
    相关资源
    最近更新 更多