未被引用的形式的记忆未被释放

时间:2014-04-29 11:20:20

标签: garbage-collection compact-framework

我创建了一个包含两个表单的简单测试程序。一个包含一个按钮来启动过程并且只包含一个图像(或在另一个测试用例中包含一个byte [])。两者都包含一个允许渲染表单的计时器。

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        timer1.Interval = 0;
    }

    private void button1_Click(object sender, EventArgs e)
    {
        timer1.Enabled = true;
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        // Instantiate and show Form2
        timer1.Enabled = false;
        var form2 = new Form2();
        form2.ShowDialog();

        // Dispose, force Collect and show (estimated) memory usage 
        form2.Dispose();
        GC.Collect();
        System.Diagnostics.Debug.WriteLine(GC.GetTotalMemory(true));
        timer1.Enabled = true;
    }
}

另一个Form只关闭自己(.designer-Part中有一个PictureBox):

public partial class Form2 : Form
{
    // Alternative test
    // private byte[] bytes;
    public Form2()
    {
        InitializeComponent();
        timer1.Interval = 0; 
        timer1.Enabled = true;
        //bytes = new byte[1024*1024];
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.Ignore;
    }
}

要点是:Form2到底是什么并不重要:内存使用率上升,一次我得到OutOfMemoryException(或者在PictureBox的情况下System.Exception结束在

at Microsoft.AGL.Common.MISC.HandleAr(PAL_ERROR ar)
at System.Drawing.Bitmap._InitFromMemoryStream(MemoryStream mstream)

但这似乎是本机调用中的OutOfMemoryException,它没有被正确抛出。)

我不明白为什么。对Form2的旧实例没有任何引用,我调用Dispose但内存未释放。

我使用CF 3.5。

1 个答案:

答案 0 :(得分:1)

好的,这里有很多东西在起作用:

  • Tick-event的事件处理程序保存了对表单的隐式引用。

timer1_Tick需要对表单的引用。只要有一个对定时器中的表单的引用和表单中指针的引用,GC(至少CF一个,我在常规Framework上测试了这个)就无法释放内存。

  • 未配置的组件。

似乎不足以在表单上调用Dispose。我还必须在Timer上调用Dispose来释放它的所有内存。 This is a bug.

public partial class Form2 : Form
{
    private byte[] bytes;
    public Form2()
    {
        InitializeComponent();
        timer1.Interval = 0; 
        timer1.Enabled = true;
        bytes = new byte[1024 * 1024];
    }

    private void timer1_Tick(object sender, EventArgs e)
    {
        this.DialogResult = DialogResult.Ignore;
        this.timer1.Tick -= timer1_Tick;
        this.timer1.Dispose();
        this.mainMenu1 = null;
    }
}