Welcome

首页 / 软件开发 / .NET编程技术 / .NET陷阱 三 “正确”使用控件也会造成内存泄露

.NET陷阱 三 “正确”使用控件也会造成内存泄露2013-05-21在我们的代码中,有时会在控件中添加对数据对象的引用。比如使用树节点的Tag属性保存相应的对象,以便在界面操作中能简单的进行访问。因为其它地方不会引用这些数据,所以我们期望在控件被销毁时,垃圾回收机制能回收相应的内存。但当软件运行了一段时间后,内存使用量会变得非常大。下面是简化后的示例代码:

using System;using System.Windows.Forms;namespace MemoryLeak{public class MainForm : Form{private Button holderButton;private Button controlButton;private FlowLayoutPanel panel;private object checkGc;public MainForm(){DumpMemoryUsage("before allocate checkGc.");checkGc = MakeLargeObject();DumpMemoryUsage("after allocate checkGc.");holderButton = new Button();holderButton.Enabled = false;holderButton.AutoSize = true;holderButton.Text = "The button holds large object.";DumpMemoryUsage("before allocate holderButton.Tag.");holderButton.Tag = MakeLargeObject();DumpMemoryUsage("after allocate holderButton.Tag.");controlButton = new Button();controlButton.AutoSize = true;controlButton.Text = "The button controls holderButton.";controlButton.Click += (sender, e) =>{DumpMemoryUsage("before release checkGc and holderButton.Tag.");panel.Controls.Remove(holderButton);holderButton.Dispose();holderButton = null;checkGc = null;DumpMemoryUsage("after release checkGc and holderButton.Tag.");};panel = new FlowLayoutPanel();panel.AutoSize = true;panel.FlowDirection = FlowDirection.TopDown;panel.Controls.Add(controlButton);panel.Controls.Add(holderButton);Controls.Add(panel);}private void DumpMemoryUsage(string msg){GC.Collect();Console.WriteLine(msg);Console.WriteLine(GC.GetTotalMemory(true));}private object MakeLargeObject(){var largeObject = new object[100];for (int i = 0; i < largeObject.Length; ++i){var array = new int[100][];largeObject[i] = array;for (int j = 0; j < array.Length; ++j){array[j] = new int[100];}}return largeObject;}}static class Program{static void Main(){Application.Run(new MainForm());}}}
代码中的checkGc变量是为了在输出中确认垃圾回收已经进行了。下面是输出结果:

before allocate checkGc.281576after allocate checkGc.4605632before allocate holderButton.Tag.4606384after allocate holderButton.Tag.8930480before release checkGc and holderButton.Tag.8940016after release checkGc and holderButton.Tag.4616824