• 转《Effective C#》Item 16:尽量减少垃圾产生的数量


    《Effective C#》Item 16:尽量减少垃圾产生的数量

    对于.Net所写一般程序来说,都属于托管程序,内存的释放和回收是由Garbage Collector完成。但是相对于栈上内存操作而言,GC回收堆上的内存,会消耗更多的CPU时间,这方面的内容可以参看这篇文章。

    http://blog.csdn.net/knight94/archive/2006/08/05/1023352.aspx

     

    因此如果让GC不停的释放和回收内存,会造成程序性能的下降。

    例如对于如下这段程序而言。

        protected override void OnPaint(PaintEventArgs e)

        {

            using( Pen penBlack = new Pen( Color.Black, 2f ) )

            {

                e.Graphics.DrawLine( penBlack, 10, 10, 100,10 );//Draw a black line

            }

            base.OnPaint (e);

        }

     

    虽说每次调用完OnPaint后,penBlack都调用了Dispose方法,但是Dispose不同于原来C或者C++Delete方法,还是需要GC去回收内存。那么当此函数频繁被调用,那么在内存中产生的垃圾就会越来越多,GC需要花很多时间去回收它们,这样会造成程序性能下降。

     

    那么,如何避免呢,或者说如何减少垃圾的产生呢。其实对象都是通过new来产生的,只要减少用new产生对象的次数,就可以减少垃圾的产生。只要把握到问题的关键点,那么相应的方法就有如下几个。

    第一个就是,使用成员而代替局部变量,对于上面的例子,可以改成如下形成。

        private Pen penBlack = new Pen( Color.Black, 2f );

        protected override void OnPaint(PaintEventArgs e)

        {

            e.Graphics.DrawLine( penBlack, 10, 10, 100,10 );//Draw a black line

            base.OnPaint (e);

        }

     

    可能很多人从C或者C++转型到使用C#,按照以前C或者C++的概念,尽量少使用全局变量,多使用局部变量;由于C#无法像C或者C++去显式释放内存,那么与其对象频繁需要GC回收,不如减少这样操作,从而造成效果会更好。

     

    第二个就是公用的对象,可以采用静态成员的方法。例如,对于上面例子中的penBlack可能其他类型也需要使用,防止在其他类型也去创建,可以采用静态全局成员,即按照如下来实现。

        public class MyPens

        {

            private static Pen penBlack;

            public static Pen Black

            {

                get

                {

                    if( penBlack == null )

                        penBlack = new Pen( Color.Black, 2f );

                    return penBlack;

                }

            }

     

            private MyPens(){}

        }

     

    对于.Net系统提供的“Pens”和“Brushes”这两个类,提供了一般常用的PenBrush.Net提供这两个静态类估计也是出于此考虑的。因此在进行绘画的时候,可以先考虑这两个类型所提供的静态对象。

     

    最后一个方法,主要是针对不可改变的原子类型,例如对于string类型来说,就是这种类型。

    例如:

        string strValue = "Hello";

        strValue += " World";

     

    对于如上的语句来说,按照一般类型来说,都会在原有对象进行处理,但是对于不可改变的原子类型而言,对于原有对象的修改,会产生新的对象。因此这两条语句会产生两个对象,第一个字符串对象是“Hello”,另一个就是“Hello World”。

     

    假如这种修改操作很频繁,那么意味着产生对象也很多,也就是说等待GC回收的垃圾就很多。为了避免此类现象发生,要么选用非原子的替代类型,要么在处理手法进行修改。

     

    对于string类型来说,替代类型为StringBuilder,这也就是为什么用StringBuilder替换string进行大型字符串操作效率高的原因。

    至于处理手法的改进,就string而言,可以采用string.Format,例如:

        string strValue = string.Format( "Total value is {0}!", nValue );

     

    方法都说完了,怎么使用在于自身灵活的掌握。不过这里要注意的一点就是,这里所说的都是针对引用类型对象,而对于在值类型来说,并不需要这样处理,因为它们分配在栈上

     

  • 相关阅读:
    [Android Pro] Fragment中使用SurfaceView切换时闪一下黑屏的解决办法
    [Android Pro] 监听Blutooth打开广播
    [Android Pro] 监听WIFI 打开广播
    [Android Pro] RecyclerView实现瀑布流效果(二)
    特征选择方法
    python pandas 计算相关系数
    dataframe 合并(append, merge, concat)
    屏幕截图
    Python 中的 sys.argv 用法
    CTPN
  • 原文地址:https://www.cnblogs.com/baiyu/p/2149602.html
Copyright © 2020-2023  润新知