zoukankan      html  css  js  c++  java
  • C# Dispose模式详细分析

    C#Dispose模式

     

    • 目的:

        为了及时释放宝贵的非托管资源和托管资源,并且保证资源在被gc回收的时候可以正确释放资源,同时兼顾执行效率

    • 必须遵循的事实:

    1 托管资源释放:
      由另一线程的gc进行释放,当托管的对象没有被引用时,就会在“适当的时候”进行回收
      如果定义了析构函数,回收的时候会调用析构函数(实际执行可能有差别),之后释放对象占用的内存。
      当类有析构函数时, gc会分分两步来释放,如果没有析构函数或者指定不需要调用析构函数时,只需要一步就能释放

    2 非托管资源必须显式释放

    • 方案:

    1.把资源释放都放在析构函数里。

    可以保证资源都释放,但是由于gc调用时机的不确定性,导致宝贵的非托管资源无法及时释放。

    2. 写个释放函数,手动是调用

    如果忘了释放的话, 托管资源会被gc释放,但非托管资源就无法释放

    3. Dispose模式。参考下面的代码

    手动调用Dispose() 可以释放所有资源,并且在gc标记不需要再调用析构函数,从而提高了效率。

    如果忘记调用Dispose(), 则当gc调用析构函数的时候也会把非托管资源释放掉

     

    -------参考代码-----------

    public interface IDisposable
    {
        void Dispose();
    }
    public class DisposablClass : IDisposable
    {
        //是否回收完毕
        bool _disposed;
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this); //标记gc不在调用析构函数
        }
        ~DisposableClass()
        {
            Dispose(false);
        }
    
        private void Dispose(bool disposing)
        {
            if(_disposed) return; //如果已经被回收,就中断执行
            if(disposing)
            {
                //TODO:释放本对象中管理的托管资源
            }
            //TODO:释放非托管资源
            _disposed = true;
        }
    }
    • 可能存在的疑问

        1. 既然gc是另外一线程执行的,为什么Dispose(bool)函数里不加锁?
         答:因为如果可以主动调用的时候,肯定此对象不是死对象,也不会被回收,因此不会同时调用到

        2. 为什么析构函数调用的dispose(false)不释放托管资源?
            答:因为析构函数由gc来调用,gc会依次释放所有的死对象(不可到达),释放的顺序是随机的,如果在一个对象的析构里调用了一个本次gc已经释放的对象,就会发生释放两次的错误。

    • 这个讲的也不错,就是有点啰嗦:

        https://blog.csdn.net/zrf2112/article/details/50644652

  • 相关阅读:
    iPhone开发教程之retain/copy/assign/setter/getter
    关于block使用的5点注意事项
    Block的引用循环问题 (ARC & non-ARC)
    浅谈iOS中MVVM的架构设计与团队协作
    JS学习笔记(不断更新)
    神经网络介绍
    JAVA WEB WITH IDEA
    百度地图标注多个点
    脑筋急转弯——Google 面试
    决策树分类器
  • 原文地址:https://www.cnblogs.com/xyzf/p/9021513.html
Copyright © 2011-2022 走看看