zoukankan      html  css  js  c++  java
  • C#内存管理之托管堆与非托管堆( reprint )

    在 .NET Framework 中,内存中的资源(即所有二进制信息的集合)分为“托管资源”和“非托管资源”。托管资源必须接受 .NET Framework 的 CLR (通用语言运行时)的管理(诸如内存类型安全性检查),而非托管资源则不必接受 .NET Framework 的 CLR 管理。(了解更多区别请参阅 .NET Framework 或 C# 的高级编程资料)托管资源在 .NET Framework 中又分别存放在两种地方:“堆栈”和“托管堆”(以下简称“堆”);规则是,所有的值类型(包括引用和对象实例)和引用类型的引用都存放在“堆栈”中,而 所有引用所代表的对象实例都保存在堆中。在C#中,释放托管资源是可以自动通过“垃圾回收器”完成的(注意,“垃圾回收”机制是 .NET Framework 的特性,而不是 C# 的),但具体来说,仍有些需要注意的地方:1、值类型(包括引用和对象实例)和引用类型的引用其实是不需要什么“垃圾回收器”来释放内存的,因为当它们出 了作用域后会自动释放所占内存(因为它们都保存在“堆栈”中,学过数据结构可知这是一种先进后出的结构);2、只有引用类型的引用所指向的对象实例才保存 在“堆”中,而堆因为是一个自由存储空间,所以它并没有像“堆栈”那样有生存期(“堆栈”的元素弹出后就代表生存期结束,也就代表释放了内存),并且非常 要注意的是,“垃圾回收器”只对这块区域起作用;3、“垃圾回收器”也许并不像许多人想象的一样会立即执行(当堆中的资源需要释放时),而是在引用类型的 引用被删除和它在"堆"中的对象实例被删除中间有个间隔,为什么呢? 因为“垃圾回收器”的调用是比较消耗系统资源的,因此不可能经常被调用!(当然,用户代码可以用方法 System.GC.Collect() 来强制执行“垃圾回收器”)然而,大多数情况下,我们需要明确地在不执行“垃圾回收器”的情况下释放托管资源(因为只需要释放一部分但又是非常需要释放的 资源,但最好不要调用“垃圾回收器”,因为“垃圾回收器”太浪费系统资源了),或需要释放“非托管资源”,这时候我们该怎么办? 这是我们写代码的时候必须要考虑的问题(“垃圾回收器”是系统自动实现的,一般情况不需要用户干预),否则 Windows 系统会因为内存耗尽而……现在,我来告诉怎么办,那就是使用类的 Dispose() 方法释放所有类型资源和使用析构方法释放非托管资源!1、Dispose() 方法要通过Dispose()方法来释放资源,那么在类定义的时候执"System.IDisposable"接口,然后在类中必须包含这样定义的方 法"void Dispose()" (在Dispose()方法中就是用户自己写的释放资源的代码段),这样一来,用户就会知道可以通过人为地调用Dispose()方法来释放资源. 不过需要注意的是,"垃圾回收器"并不是通过调用Dispose()方法来释放托管资源的!2、析构方法在 C# 中定义析构方法的格式是“~CLASS_NAME()”。非常需要注意的是,如果一个类中没有使用到非托管资源,那么请一定不要定义析构方法,这是因为对 象执行了析构方法,那么“垃圾回收器”在释放托管资源之前要先调用析构方法,然后第二次才真正释放托管资源,这样一来,两次删除动作的花销比一次大多的! (不过,即使你在类中已经定义了析构方法,仍然有办法“屏蔽”它,这将在后面的代码范例中说明)在析构方法中,就是用户自己写的释放非托管资源的代码段。 下面使用一段代码来示范 Dispose() 方法和析构方法如何使用: 

       public class ResourceHolder : System.IDisposable    {        public void Dispose()        {            Dispose(true);            System.GC.SuppressFinalize(this);            // 上面一行代码作用是防止"垃圾回收器"调用这个类中的方法            // “~ResourceHolder()”            // 为什么要防止呢? 因为如果用户记得调用 Dispose() 方法,那么            // “垃圾回收器”就没有必要"多此一举"地再去释放一遍“非托管资源”了            // 如果用户不记得调用呢,就让“垃圾回收器”帮我们去“多此一举”吧 ^_^            // 你看不懂我上面说的不要紧,下面我还有更详细的解释呢!        }        protected virtual void Dispose(bool disposing)        {            if (disposing)            {                // 这里是清理“托管资源”的用户代码段            }            // 这里是清理“非托管资源”的用户代码 段        }        ~ResourceHolder()        {            Dispose(false);        }    } 上面的代码是一个典型的有两种 Dispose 方法的类定义。在 .NET Framework 中有很多系统类是用这种方法定义 Dispose() 方法的,例如:MSDN 中,System.Drawing.Brush.Dispose 方法就是这样定义的:************************************************************* 释放由此 Brush 对象使用的所有资源。                      ** public void Dispose()                                    ** 该成员支持 .NET 框架结构,因此不适用于直接从代码中使用。 ** protected virtual void Dispose(bool);                    ************************************************************* 这里,我们必须要清楚,需要用户调用的是方法 Dispose() 而不是方法 Dispose(bool),然而,这里真正执行释放工作的方法却并不是 Dispose(),而是 Dispose(bool) !为什么呢?仔细看代码,在 Dispose() 中,调用了 Dispose(true),而参数为“true”时,作用是清理所有的托管资源和非托管资源;大家一定还记得我前面才说过,“使用析构方法是用来释放非 托管资源的”,那么这里既然 Dispose() 可以完成释放非托管资源的工作,还要析构方法干什么呢?其实,析构方法的作用仅仅是一个“备份”!为什么呢?严格地说,凡执行了接口 “IDisposable”的类,那么只要程序员在代码中使用了这个类的对象实例,那么早晚得调用这个类的 Dispose() 方法,同时,如果类中含有对非托管资源的使用,那么也必须释放非托管资源! 可惜,如果释放非托管资源的代码放在析构方法中(上面的例子对应的是 “~ResourceHolder()”),那么程序员想调用这段释放代码是不可能做到的(因为析构方法不能被用户调用,只能被系统,确切说是“垃圾回收 器”调用),所以大家应该知道为什么上面例子中“清理非托管资源的用户代码段”是在 Dispose(bool) 中,而不是 ~ResourceHolder() 中!不过不幸的是,并不是所有的程序员都时刻小心地记得调用 Dispose() 方法,万一程序员忘记调用此方法,托管资源当然没问题,早晚会有“垃圾回收器”来回收(只不过会推迟一会儿),那么非托管资源呢?它可不受 CLR 的控制啊!难道它所占用的非托管资源就永远不能释放了吗?当然不是!我们还有“析构方法”呢!如果忘记调用 Dispose(),那么“垃圾回收器”也会调用“析构方法”来释放非托管资源的!(多说一句废话,如果程序员记得调用 Dispose() 的话,那么代码 System.GC.SuppressFinalize(this) 则可以防止“垃圾回收器”调用析构方法,这样就不必多释放一次“非托管资源”了) 所以我们就不怕程序员忘记调用 Dispose() 方法了。所以我说了这么一大堆的理由,综合起来只有两点:*1、程序员们啊,千万不要忘记调用 Dispose() 方法!(如果有的话 ^_^)*2、万一忘记,不要着急……还有救!!!因为还有“垃圾回收器”帮我们自动调用析构方法!
  • 相关阅读:
    [kuangbin带你飞]专题十二 基础DP1 E
    hdu 1203 I NEED A OFFER! (01背包)
    hdu 2602 Bone Collector (01背包)
    hdu 4513 吉哥系列故事——完美队形II (manacher)
    hdu 2203 亲和串 (KMP)
    hdu 1686 Oulipo (KMP)
    hdu 1251 统计难题 (字典树)
    hdu 2846 Repository (字典树)
    hdu 1711 Number Sequence (KMP)
    poj 3461 Oulipo(KMP)
  • 原文地址:https://www.cnblogs.com/zhaoxinshanwei/p/4035224.html
Copyright © 2011-2022 走看看