Properly disposing of, and removing references to UserControls, to avoid memory leak

烂漫一生 提交于 2019-11-27 20:41:49
foreach (Control control in flowPanel.Controls) {
    if (control != NodeEditPanel.RootNodePanel) {
        control.Dispose();
    }
}
flowPanel.Controls.Clear();

This is a pretty classic Winforms bug, many programmers have been bitten by it. Disposing a control also removes it from the parent's Control collection. Most .NET collection classes trigger an InvalidOperationException when iterating them changes the collection but that wasn't done for the ControlCollection class. The effect is that your foreach loop skips elements, it only disposes the even-numbered controls.

You already discovered the problem, but made it considerably worse by calling Controls.Clear(). Extra-specially nasty because the garbage collector will not finalize the controls that are removed that way. After the native window handle for a control is created, it will stay referenced by an internal table that maps Window handles to controls. Only destroying the native window removes the reference from that table. That never happens in code like this, calling Dispose() is a rock hard requirement. Very unusual in .NET.

The solution is to iterate the Controls collection backwards so that disposing controls doesn't affect what you iterate. Like this:

for (int ix = flowPanel.Controls.Count-1; ix >= 0; --ix) {
    var ctl = flowPanel.Controls[ix];
    if (ctl != NodeEditPanel.RootNodePanel) ctl.Dispose();
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!