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

    回到目录

    为何要写

    之所以写这篇文章,完全是因为学生们在实际开发中遇到的问题,一个对象占用的内存空间总不被释放,导致系统内存不断攀升,其最主要原因是我们对“对象的生与死”不清楚,或者从来没有认真去考虑过这件事,确实一个对象在被声音,初始化,使用或者最后被系统回收,整个的过程与我们关系确实不大,我们开发人员直接用就行了,对于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里就行了,简单!

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

    谢谢阅读!

    回到目录 

  • 相关阅读:
    vmware ubuntu 异常关机无法连接到网络
    Speed up GCC link
    常用的一些解压命令
    Log4j 漏洞复现
    Test Case Design method Boundary value analysis and Equivalence partitioning
    CCA (Citrix Certified Administrator) exam of “Implementing Citrix XenDesktop 4”
    What is Key Word driven Testing?
    SAP AGS面试小结
    腾讯2013终端实习生一面
    指针的引用
  • 原文地址:https://www.cnblogs.com/lori/p/5395533.html
Copyright © 2011-2022 走看看