2

我试图在以下代码中找出 tmpTabPages 的生命周期。让我们假设表单有一个名为 MyTabControl 的空 TabControl,即有一个名为 NameCollection 的字符串集合。

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    For Each itm In NameCollection
        Dim tmpTabPage as New TabPage(itm.toString)

        'Add Controls to tmpTabPage

        MyTabControl.TabPages.Add(tmpTabPage)
    Next
End Sub

由于 tmpTabPage 的范围是 For/Next 块,通常它的生命周期会一直到块结束,对吧?但是,由于它被添加到具有块之外范围的集合中,它是否获得与集合相同的生命周期,或者在这种情况下是 MyTabControl?最后,如果我调用 MyTabControl.TabPages.Clear 集合中的 tmpTabPages 是否会被销毁,或者它们会坐在那里占用内存?

4

4 回答 4

5

从 Control 派生的类(包括 TabPage)最重要的是 Dispose() 方法。它们不受自动垃圾收集的影响,Winforms 保留一个将控件的句柄映射到控件引用的内部表。这就是为什么,比如说,你的主窗体不会突然被垃圾收集,即使你的程序没有保留对它的引用。

将 TabPage 添加到 TabControl 的集合中会自动处理。TabControl 也是如此,它将被添加到表单的 Controls 集合中。正常的事件链是您的程序或用户关闭表单。Form 类迭代其子控件并调用它们的 Dispose() 方法。TabControl 在它的 Dispose() 方法中做同样的事情,处理标签页。Windows 窗口在此过程中被破坏,从该映射表中删除句柄,现在允许垃圾收集器最终收集控件的托管包装器。

有一个令人讨厌的陷阱让许多 Winforms 程序员陷入困境。如果您从其父集合中删除一个控件,那么您有责任自己处置它。删除它不会自动处置它。Winforms 通过临时将控件重新设置为名为“停车窗口”的隐藏窗口来保持本机窗口活动。不错的功能,它允许您将控件从一个父级移动到另一个父级,而无需销毁和重新创建控件。

但是那里的关键词是“暂时的”。如果您下一次重新设置控件,这只是暂时的。所以它从停车窗口移动到新的父窗口。如果您实际上不重新设置它,那么它将在停车窗口上永远保持活力。吞噬资源直到程序终止。这也称为泄漏。当您已经创建了 10,000 个窗口时,如果 Windows 拒绝创建另一个窗口,它可能会使您的程序崩溃。

ControlCollection.Clear() 方法在这里尤其有害。它不处理控件,它们都被移动到那个停车窗口。如果这不是故意的,很少是这样,您必须自己调用 Dispose() 。

于 2010-11-16T14:39:14.623 回答
3

.NET 中的对象在无法获取它们时就可以进行垃圾回收。在这种情况下,有一种方法可以TabPage通过TabPages集合获取,直到它从集合中删除或选项卡控件本身变得有资格进行集合。

现在,当一个对象有资格进行垃圾收集时,这并不意味着它会立即被垃圾收集——垃圾收集根据一些相当复杂的启发式方法在不同的时间运行,并且还有“世代”的内存使事情变得更难预测.

但基本上:

  • 您不必担心已添加到集合中的对象会被神秘地收集并导致问题
  • 您通常不必担心对象会永远泄漏内存。在某些情况下,您确实需要采取一些积极的步骤来确保当您不再使用某个对象时该对象符合收集条件,但这种情况相对较少。(根据我的经验,它们通常与静态变量和/或事件有关。)
于 2010-11-16T13:58:21.570 回答
0

因为某些东西引用了它们不会被处理的控件。

是的,如果您没有将对它们的引用添加到集合中,则生命周期将持续到程序结束。

清除将从集合中删除对象,并且如果没有其他对它们的引用,它们将被垃圾收集(在您描述的情况下不应该出现这种情况)

于 2010-11-16T13:58:30.237 回答
0

您只将 TabPage 对象的引用添加到集合而不是对象 TmpTabPage。在这种情况下,tmpTabPage 对象仅用于分配内存。

于 2010-11-16T14:01:12.223 回答