zoukankan      html  css  js  c++  java
  • C# 基础才是重中之重~对象的生与死

     

    为何要写

    之所以写这篇文章,完全是因为学生们在实际开发中遇到的问题,一个对象占用的内存空间总不被释放,导致系统内存不断攀升,其最主要原因是我们对“对象的生与死”不清楚,或者从来没有认真去考虑过这件事,确实一个对象在被声音,初始化,使用或者最后被系统回收,整个的过程与我们关系确实不大,我们开发人员直接用就行了,对于C#这种托管语言你没必要去自己回收它,但有时,我们多了解一点系统的回收机制,对我们的程序还是很有好处的。

    对象的种类(根据作用域)

    1 类对象,静态对象,使用static修饰符进行声明,作用域为整个类(所有实体公有),当你的程序运行期间它一直不会被回收,直到你的进程结束(所以使用它要注册,大数据一般不用类对象存储)

    2 类级别的实例对象,它定义在类里,方法体外面,作用域为整个类的当前实例,它的回收时机我们无法确定,当然你可以手动进行  GC.Collect()来马上释放它,否则由系统的垃圾回收机制管理它

    3 方法级别的实例对象,局部对象,它定义在方法内部,作用域为当前方法体,方法执行完成后,自动释放

    代码中的实验

    复制代码
        public class Product
        {
            ~Product()
            {
                Logger.LoggerFactory.Instance.Logger_Info("Product对象已经被释放");
            }
            public int ID { get; set; }
            public string Name { get; set; }
        }
    
        public class ProductConfig
        {
            ~ProductConfig()
            {
                Logger.LoggerFactory.Instance.Logger_Info("ProductConfig对象已经被释放");
            }
            public int ID { get; set; }
            public string Name { get; set; }
        }
    复制代码
    复制代码
            /// <summary>
            /// 类级别的
            /// </summary>
            ProductConfig productConfig = new ProductConfig();
            public ActionResult Create()
            {
                /// <summary>
                /// 实例成员,方法体里
                /// </summary>
                Product product = new Product();
                GC.Collect();//清除全局实例成员,否则全局实例对象将不会马上清楚,它会等待垃圾回收
                return View();
            }
    复制代码

    上面代码在执行后,会写入日志文件,由于在方法里使用了GC.Collect()方法,这时全局实例对象ProductConfig将会在方法执行后被释放,如果不加这个方法,那么ProductConfig何时释放,我们是不知道的。

    Dispose模式

    对上面的操作是我们刻意去进行的,意思就是让大家看到,对象何时会被释放,而对象在被释放后,会执行类的析构方法(~开头的),它在C#里很少被使用,或者我们很少关注它,因为你不去实现它,系统垃圾回收结束后也会去调用它,这是对于托管资源说的,我们在C#这个开发语言里,有时也会涉及到使用一些“非托管”资源,比如数据库连接,网络通讯,文件访问等等,它们是不受当前Frameworks CLR控制的,或者说CLR也控制不了它,因为它已经脱离了当前应用程序,这也算是合情合理,这时,这些非托管资源会实现自己的“资源释放”方法,好Dispose,大家如果有心的话,都会发现像文件,SQL连接,socket,Tcp等对象,都有Dispose方法,它的意思就是释放当前对象,而我们在使用它们时,如何把非托管与托管对象结合起来,一起把对象释放呢,这就是现在要说的Dispose模式

    复制代码
       /// <summary>
        /// 实现IDisposable,对非托管系统进行资源回收
        /// 作者:仓储大叔
        /// </summary>
        public abstract class DisposableBase : IDisposable
        {
            /// <summary>
            /// 标准Dispose,外界可以直接调用它
            /// </summary>
            public void Dispose()
            {
                Logger.LoggerFactory.Instance.Logger_Debug("Dispose");
    
                this.Dispose(true);////释放托管资源
                GC.SuppressFinalize(this);//请求系统不要调用指定对象的终结器. //该方法在对象头中设置一个位,系统在调用终结器时将检查这个位
            }
    
            private void Dispose(bool disposing)
            {
                if (!_isDisposed)//_isDisposed为false表示没有进行手动dispose
                {
                    //清理托管资源和清理非托管资源
                    Finalize(disposing);
                }
                Logger.LoggerFactory.Instance.Logger_Debug("Dispose complete!");
                _isDisposed = true;
            }
    
            /// <summary>
            /// 由子类自己去实现自己的Dispose逻辑(清理托管和非托管资源)
            /// </summary>
            /// <param name="disposing"></param>
            protected abstract void Finalize(bool disposing);
    
            private bool _isDisposed;
    
            /// <summary>
            /// 是否完成了资源的释放
            /// </summary>
            public bool IsDisposed
            {
                get { return this._isDisposed; }
            }
            /// <summary>
            /// 析构方法-在类被释放前被执行
            /// </summary>
            ~DisposableBase()
            {
                Logger.LoggerFactory.Instance.Logger_Debug("析构方法");
    
                //执行到这里,托管资源已经被释放
                this.Dispose(false);//释放非托管资源,托管资源由终极器自己完成了
            }
        }
    复制代码

    使用它

    复制代码
      public class ZzlTools : DisposableBase
        {
    
            protected override void Finalize(bool disposing)
            {
                if (!disposing)
                {
                    //清除托管
                }
                //清理非托管
            }
        }
    复制代码

    通过大叔整理的Dispose基类,我们可以看到,外界的对象只要实现Finalize方法即可,把自己需要释放的对象写在Finalize里就行了,简单!

    最后,和大家分享我的一个经验,学习基础知识,就像修炼内功,我们一定要打好根基,才能更上一层楼!

  • 相关阅读:
    [转]BIOS中断汇编函数---留用
    SWT/JFace 按键、事件、监听
    erlang局域网内通信
    ios热修复
    swift里面!和?的作用
    AFNetworking上传下载图片
    横向滚动的UITableView
    判断iphone手机型号
    iPhone屏幕尺寸、分辨率及适配
    UITapGestureRecognizer 和UIPanGestureRecognizer的使用,触摸和滑动
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/5509024.html
Copyright © 2011-2022 走看看