在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
我们知道:C#是一门虚拟机语言,C#编译器首先将C#代码编译成IL代码,运行程序时CLR(Common Language Runtime,公共语言运行时)通过调用JIT(just-in-time Compiler,即时编译器)来将IL代动态即时编译成可执行的机器码。GC(Garbage Collector,垃圾收集器)自动为我们的应用程序进行内存管理的分配和释放,(具体参见:了解.NET 内存管理机制),以一种高效的方式来移除内存中的垃圾对象,不过不管有多高效,分配和销毁在堆上的对象总会花费掉时间。 如果我们在一个方法中创建了过多的引用对象,会对应用程序的性能产生严重的影响。因此我们应该遵守下面的一些规则,可以尽量的降低GC的工作量。
阅读目录:
1.将常用的局部变量提升为成员变量所有的引用类型,包括那些局部变量,都会分配到堆上。在函数退出后,函数内的所有局部变量都会立即变成垃圾对象。所以我们可以得出结论:
在GUI编程中一个常见的错误就是:在窗体的Paint处理函数中创建GDI(Graphics Device Interface,图形设备接口)对象,如下: 1 protected override void OnPaint(PaintEventArgs e) 2 { 3 using (Font myFont = new Font("Arial", 10.0f)) 4 { 5 e.Graphics.DrawString(DateTime.Now.ToString(), myFont, Brushes.Black, new Point(0, 0)); 6 } 7 base.OnPaint(e); 8 }
OnPaint()将会被非常频繁的调用,每次调用都会创建一个Font对象,而包含的内容完全和上一次一样。所以GC需要每次都为你清扫这些垃圾,严重影响了应用程序的效率。其实我们完全可以将Font对象提升为成员变量,是每次窗体重绘时能够重用该Font对象: 1 private readonly Font myFont = new Font("Arial", 10.0f); 2 3 protected override void OnPaint(PaintEventArgs e) 4 { 5 e.Graphics.DrawString(DateTime.Now.ToString(), myFont, Brushes.Black, new Point(0, 0)); 6 7 base.OnPaint(e); 8 } 将常用的局部变量提升为成员变量之后,程序无需每次重绘时生成垃圾对象,减轻了GC的负担,也提升了程序的效率。不过这里有一个小小的限制:将实现了IDisposable接口的局部变量提升为成员变量,那么这个成员变量依附类本身也需要实现IDisposable接口。
2.为常用的类型实例提供静态对象静态成员变量可以让引用类型在类的各个实例中共享。我们可以通过提供了一个类,存放某个类型常用的实例的单例对象,这样可以避免创建重复的对象。.NET Framework 的类库中就有很多这样的做法:Brushes类包含了一系列的静态Brush对象,每个都包含了一种常用的颜色。它们的简要实现如下: 1 private static Brush blackBrush; 2 public static Brush Black 3 { 4 get 5 { 6 if (blackBrush == null) 7 blackBrush = new SolidBrush(Color.Black); 8 return blackBrush; 9 } 10 } 在第一次请求黑色画刷时,Brushes将创建一个实例,随意Brushes类将保留该实例的引用,并在后续的请求时直接返回同一个句柄。也就是说我们只创建了一个黑色画刷,然后一直重用这个对象。至于其他的例如:红色的画刷,如果应用程序没有使用这个资源那么该对象也不会被分配。.NET 提供的这种方式能够在满足需求的前提下尽可能的少创建对象,我们在自己的应用程序中也应该这样做。
3.为不可变类型提供可变的创建对象System.String类型时一个不可变类型:即在构造一个字符串对象后,其内容不能被修改。如果对一个字符串进行修改时,实际上时创建了一个新的字符串对象,从前的字符串对象也就变成了垃圾。看下面的代码: 1 //How are you? 2 string msg = "How"; 3 msg += " are"; 4 msg += " you"; 5 msg += "?";
string类型的+=操作符会创建一个新的字符串对象并返回,对于这类拼接字符串的工作应该交给更适合的string.Format()方法: 1 string msg = string.Format("{0} {1} {2}{3}", "How", "are", "you", "?");
如果需要进行一些比简单拼接字符串更加复杂的工作,可以考虑使用StringBuilder类,该类是一个可变的字符串,用来创建不可变的string对象。对于经常变化的stirng对象,使用StringBuilder对象来替换是一个非常好的选择 —— 当我们的某个设计需要不可变类型时,应该考虑提供一个创建对象,专门负责分步地构造出最终对象(例如:string对象之于StringBuilder对象)。这样既可让用户分步地创建出最终对象,也可以保证对象的不可变性。
小节
|
请发表评论