C# windows窗体中的C垃圾收集

C# windows窗体中的C垃圾收集,c#,garbage-collection,C#,Garbage Collection,我有两个windows窗体frmMain和frmDialog。当我单击frmMain上的按钮时,frmDialog打开。以下是我的按钮点击事件代码: frmDialog f2 = new frmDialog(); f2.Show(); 当我继续点击按钮时,新表单出现&不关闭。对象超出作用域时会被垃圾收集 我的问题是: 为什么变量f2超出范围时不进行垃圾收集 是内存泄漏吗?有个窍门。调用Show时,Visible属性设置为true,这反过来调用SetVisibleCore: 有趣的是: if

我有两个windows窗体frmMain和frmDialog。当我单击frmMain上的按钮时,frmDialog打开。以下是我的按钮点击事件代码:

frmDialog f2 = new frmDialog();

f2.Show();
当我继续点击按钮时,新表单出现&不关闭。对象超出作用域时会被垃圾收集

我的问题是:

为什么变量f2超出范围时不进行垃圾收集


是内存泄漏吗?

有个窍门。调用Show时,Visible属性设置为true,这反过来调用SetVisibleCore:

有趣的是:

if (CalledOnLoad) {
    // VSWhidbey 518085: make sure the form is in the Application.OpenForms collection
    if (!Application.OpenFormsInternal.Contains(this)) {
        Application.OpenFormsInternalAdd(this);
    }
}
表单将添加到存储在静态属性中的集合中。因此,在关闭并自动从该收集中删除之前,您的表单将被根化,并且没有资格进行垃圾收集

根据Hans Passant的评论,我玩了一个内存转储:

0:000> !gcroot 000000000263d368
HandleTable:
0000000000191348 (strong handle)
-> 000000000263d368 WindowsFormsApp1.Form1

00000000001917d0 (pinned handle)
-> 00000000125f99a8 System.Object[]
-> 000000000262c9a8 System.Windows.Forms.FormCollection
-> 000000000262c9d8 System.Collections.ArrayList
-> 000000000262ca00 System.Object[]
-> 000000000263d368 WindowsFormsApp1.Form1

我们看到Application.OpenFormsInternal集合是第二个根,但它也是一个强大的句柄,即使它不在集合中也会保持窗体的活动状态,这是内存泄漏

在C语言中,你有两种记忆。托管内存和非托管内存。托管内存由GC管理:非托管内存不是。您必须自己释放非托管内存。例如:

{
    List<int> l = new List<int(); 
}
这是内存泄漏。当f超出作用域时,它的非托管内存根本不由GC管理。所以你必须自己释放它:

{
    MyForm f = new MyForm();
    f.ShowDialog();
    f.Dispose();
}
Dispose方法释放所有未经管理的内存。现在你可能有两个问题: 1.如何知道类是托管的还是非托管的? 这很简单。您可以假设实现IDisposable接口包含Dispose方法的所有类都是非托管的—它们本身是非托管的,或者由非托管类组成。特别是字体、流、表单、数据库连接等各种资源

我应该如何释放非模态形式? 您可以存储对该表单的引用,并在不再需要时对其进行处理。您可以在FormClosed事件中调用Dispose
你曾经关闭过表格吗?你的问题没有说清楚。new frmDialog不应该创建新的表单实例吗?垃圾收集与显示窗口无关。此外,对象在超出范围时被垃圾回收是不正确的。更接近正确的说法是,当可以证明不再使用某个对象时,该对象就有资格被收集。这可以早于范围的结束,也可以仅说明资格。无法保证对象何时被收集。@Smartis-只要你,不管你是什么意思,不符合收集条件。当我关闭frmMain时,frmMain以及所有对话框close看起来都令人信服,但是。参考值保持在较低的水平。查看NativeWindow.CreateHandle,您将找到HandleCollector类。@HansPassant噢。我在第一根上停了下来,我想我应该挖得更深一些。
{
    MyForm f = new MyForm();
    f.ShowDialog();
    f.Dispose();
}