2

我可能不明白这个概念,或者我做错了什么。我对 .NET 中的内存管理有一些疑问。

想象一下情况:

Form1是大人物 Form,作为 MDI-parent 和 a little FormChild,被绑定为孩子:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void simpleButton1_Click(object sender, EventArgs e)
        {
            FormChild formChild = new FormChild();

            formChild.MdiParent = this;
            formChild.Show();

        }
    }

现在孩子正在分配一点内存作为模拟:

public partial class FormChild : Form
{
    private readonly List<byte[]> _list = new List<byte[]>();

    public FormChild()
    {
        InitializeComponent();


    }

    private void FormChild_Load(object sender, EventArgs e)
    {
        int i = 0;
        while (i < 100)
        {
            _list.Add(new byte[1024 * 1024 * 10]);
            i += 1;
        }

    }

}

现在,我正在使用内存分析器检查内存堆中发生了什么。我明白了,如果我点击按钮,内存就被分配了。然后我关闭FormChild它,它会调用Dispose(). 但是内存仍然被分配。如果我再次单击System.OutOfMemoryException会发生。

为什么 GC 等待释放托管内存?或者这是我的设计错误?

4

4 回答 4

6

GC只是为了响应内存压力而释放内存,Dispose的主要目的是清理非内存相关的资源。

换句话说,将托管对象清零并不一定会使它们被更快地收集,但会使诊断内存问题更容易诊断。

于 2012-09-18T17:40:31.770 回答
3

它看起来像某种时间问题,formChild 的第一个实例仍然可以访问(即不是垃圾),而第二个实例被创建。你不能容纳_list两次。

请注意,我关闭了 FormChild,它调用 Dispose()是关于资源和窗口句柄的语句,而不是关于释放内存的语句。

目前尚不清楚您是否编写了自己的 Dispose() 但在这种(相当特殊的)情况下,您应该这样做。

  • void Dispose(bool disposing)从文件中剪切方法FormChild.Designer.cs并将其移动到FormChild.cs.

  • 用它来释放巨大的内存块:

    protected override void Dispose(bool disposing)
    {
        _list = null;  // add this
    
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }
    

请注意,这不是一种“通常”的内存管理形式,但它是必需的,因为您的 _list 也很不寻常。

于 2012-09-18T18:40:24.823 回答
0

您可以使用 GC.Collect ( http://msdn.microsoft.com/en-us/library/xe0c2357.aspx )立即执行垃圾收集

但是,我通常让它自己处理并实现 Dispose 方法。

于 2012-09-18T18:03:42.640 回答
-1

覆盖DisposeFormChild以便您可以清理资源。

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        if (_list != null)
        {
            // Clear it, dispose it, do whatever you want with it.
        }
    }

    base.Dispose(disposing);
}

正如 Yaur 所说,GC 在调用时不会立即清理内存Dispose,但最好的做法是尽可能清理。

于 2012-09-18T17:44:20.570 回答