zoukankan      html  css  js  c++  java
  • 【设计原则和建议】 构造和析构对象


    良好的构造和析构对象,控制对象生命周期可以较大的提高程序的性能,降低GC的压力,减少BUG几率。

    本文还是比较简单的,主要还是经验的总结,很多东西也许各位已经知道,也许不知道。希望大家一起讨论。

     
     

      

    1.如果可能,避免静态构造函数 (也成为类型构造函数)

    • 性能原因 (不过因为一个类的静态构造函数只会执行一次,这不是一个大问题)
    • 静态构造函数不应该抛出异常

    2.如果可以,构造函数应该尽可能轻量级

    • 职责上说,构造函数只应该构造出一个对象,而不是执行一大堆初始化等的操作
    • 如果有很重量级的代码,用静态方法Create出来 例如WebRequest.Create

    3.一个常识,调用构造函数时,会先调用父类的构造函数
     

    4.一个类必须输入的参数请放在构造函数的输入参数中(或Create方法)

    • 主要是逻辑和保障执行顺序的原因
    • 不要构造完了以后一个个属性去赋值

    5.如果要按照顺序初始化私有成员,请在构造函数中进行 (或Create方法)

    • 虽然目前CLR是从上至下的初始化私有成员,但是不保证将来版本的初始化顺序也是一样的
    • 某些第三方工具自动格式化代码的时候会改变

    6.构造函数中不应该调用虚方法

    7.使用this()和base()可以方便构造函数之间的相互调用
     

    8.不要在不必要的情况下构造对象 (虽然有可能被优化掉)

    DataSet ds = new DataSet();
    ds = SqlHelper.ExecuteDataSet("select * from table1");

    9.在更考虑性能的情况下,缩短对象生命周期 (大部分程序都不会这么考虑性能)

    • 尽量迟的初始化
    • 尽量早的销毁对象
    • 尽量小的作用域
    • 如果对象有可能被复用,研究一下GC的对象复活
    • 一个小提示
    •             SingletonClass item1 = null;
      for (int i = 0; i < 100; i++)
      {
      SingletonClass item2 = null;//在这两个地方声明,没有区别,被优化掉了
      }

    10.如果对象实现了IDisposable

    • 请使用using 或者直接调用Dispose
    • 有些系统对象实现了Close, 其实Close内部就是调用了Dispose()

    11.如果想实现一个IDisposable

      简单的实现

      class ConstructorDemo : IDisposable

        {
    public void Dispose()
    {
    Dispose(true);
    GC.SuppressFinalize(this); //告诉CLR不要调用Finalize 这是一个非常消耗性能的方法
    }

    private void Dispose(bool disposing)
    {
    if (!disposing)
    {
    //清理托管资源
    }
    //清理非托管资源
    }
    }

      完整的实现 http://msdn.microsoft.com/en-us/library/b1yfkh5e.aspx

    12.如果想实现Singleton

    View Code
        public class ConstructorDemo1
    {
    private static SingletonClass singleton = new SingletonClass();
    //简单的类 我最喜欢用这种方式了,不够构造函数出问题了就很讨厌了
    //只初始化一次 不用太关心性能问题
    //如果SingletonClass构造函数抛出异常 那就完蛋了

    private ConstructorDemo1()
    {
    }
    public SingletonClass Create()
    {
    return singleton;
    }
    }

    public class ConstructorDemo2
    {
    private static SingletonClass singleton = null;
    private static object asyncLock = new object();
    private ConstructorDemo2()
    {
    }
    public SingletonClass Create()//只初始化一次 不用太关心性能问题,初始化有问题可以在这里处理啊
    {
    if (singleton == null)
    {
    lock (asyncLock)
    {
    if (singleton == null)
    {
    singleton = new SingletonClass();
    }
    }
    }
    return singleton;
    }
    }

    public class ConstructorDemo3
    {
    private static Lazy<SingletonClass> singleton = new Lazy<SingletonClass>();
    private ConstructorDemo3()
    {
    }
    public SingletonClass Create()
    {
    return singleton.Value;//4.0 还是这样简单
    }
    }


    13.了解GC的大致原理将有利于设计出符合预期的程序

    • 建议参考CLR via C#
    • 如果不想被GC的最简单方式把对象放在一个static 成员上
    • 一个例子关于资源被意外回收
    using System;
    using System.Threading;
    public static class Program
    {
    public static void Main()
    {
    //注意要在Release模式下跑
    Timer t = new Timer(TimerCallback, null, 0, 2000);
    Console.ReadLine();
    }
    private static void TimerCallback(Object o)
    {
    Console.WriteLine("In TimerCallback: " + DateTime.Now);
    GC.Collect(); //触发GC
    }
    }


    14.一般不使用析构函数释放资源

    • 微软推荐用析构函数释放非托管资源 (例如文件,网络连接)
    • 我个人建议是最好都别用析构,而是显式回收资源(IDisposable),因为析构内部是调用Finalize ,而这东西的运行时间是不确定的。。。而且还有性能问题
    View Code
        public class Deconstructor
    {

    //非常不推荐使用Finalize,主要问题就是其调用时间是不确定的,并且有性能问题
    ~Deconstructor()
    {
    // 清理代码 //将被转换为下面的代码
    }
    //protected override void Finalize()
    //{
    // try
    // {
    //// 清理代码
    // }
    // finally
    // {
    // base.Finalize();
    // }
    //}
    }

    15.不要创建大量的小对象

    • 例如string
    • 例如WCF,webservice中序列化反序列化

    PS: GC.SuppressFinalize 经常在Dispose被调用, 用于通知CLR:我自己会搞定,你不要调用Finalize

    PS: GC有workstation和server模式

    PS: 有GC也是会存在内存泄漏的,一般常见用有些对象一直被引用 所以无法被GC

    PS: GC超时也会抛出OutOfMemoryException, 不一定是真的没有内存了

    PS:使用DotNetTrace 之类的工具分析内存中都存在什么对象,也可以分析构造和析构函数的性能

    PS:使用WinDBG+SOS分析内存也很不错(特别是生产环境)

    PS:我个人喜欢静态方法胜于实例方法(不喜欢每次构造对象),除非是设计需要,或者逻辑上应该是实例方法

    部分资料来源于网络,因为本人水平有钱,如有谬误还请指正。

  • 相关阅读:
    javaBean的理解
    配置tomcat8数据源(采用局部数据源方式)
    windows下apache报os 10048错误
    Windows下Apache的下载安装启动停止
    java通过数据库连接池链接oracle
    java连接oracle数据库
    eclipse配置svn方法
    JAVA多线程中start方法与run方法区别
    java程序在没有java环境的电脑上执行的方法(关键词jar,exe)
    js监听不到组合键
  • 原文地址:https://www.cnblogs.com/PurpleTide/p/2214038.html
Copyright © 2011-2022 走看看