虽然.NET提供了垃圾回收机制,可以对托管的资源进行管理,但是创建对象和销毁对象本身,也是要花费时间的,特别是对于引用类型来说,频繁的创建和销毁引用类型的对象,对性能来说,是非常不好的。
我们可以采取一些措施,来改善这种情况。
首先,来看下面的代码。
代码
如果OnPaint()方法被频繁调用,那么每次调用它时,程序都会创建一个包含相同设置的Font对象,而且在每次退出方法时,垃圾回收器都要删除它们,这样做事很没有效率的。
1 protected override void OnPaint( PaintEventArgs e )
2 {
3 // Bad. Created the same font every paint event.
4 using ( Font MyFont = new Font( "Arial", 10.0f ))
5 {
6 e.Graphics.DrawString( DateTime.Now.ToString(),
7 MyFont, Brushes.Black, new PointF( 0,0 ));
8 }
9 base.OnPaint( e );
10 }
我们可以将上面代码中的Font对象重构为类的成员变量,这样在调用OnPaint()方法时,就可以重用Font对象。
代码
当方法中的局部变量包含引用类型并且该方法会被频繁调用时,我们可以将引用类型的变量由局部变量提升为类型的成员变量,这种方式对于值类型来说,是没有必要的。
1 private readonly Font _myFont =
2 new Font( "Arial", 10.0f );
3
4 protected override void OnPaint( PaintEventArgs e )
5 {
6 e.Graphics.DrawString( DateTime.Now.ToString( ),
7 _myFont, Brushes.Black, new PointF( 0,0 ));
8 base.OnPaint( e );
9 }
然后,针对平时一些常用的引用类型,我们可以构建该类型的静态实例,这样可以保证类型只被实例化一次。另外,为了提升性能,可以对类型的实例实行延迟加载的策略,只在用到的时候,才会被加载。
最后,当我们构造常量类型的固定值时,例如string,因为对string类型执行+=操作,就相当于重新创建一个string实例,这样在构造的过程中,会产生大量string中间实例,为了减少string实例的数目,我们可以使用stringbuilder来初始化。
总结:垃圾收集器在管理应用程序所使用的内存方法非常有效,但是,记住创建和销毁对象仍然需要花费时间。我们应该避免创建过多的对象;不要创建不需要的对象。也要避免在局部方法内部创建多个引用类型的对象,相反,我们应该考虑将局部变量提升为类型的成员变量,或者为类型中的绝大多数常用类型创建一些静态实例,最后,对于具有常量性的类型,我们应该考虑为它们创建一个支持可变的生成类型。