在 .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、万一忘记,不要着急……还有救!!!因为还有“垃圾回收器”帮我们自动调用析构方法!

C#内存管理之托管堆与非托管堆( reprint )的更多相关文章

  1. C# 托管资源与非托管资源

    在.net 编程环境中,系统的资源分为托管资源和非托管资源. 托管资源: Net平台中,CLR为程序员提供了一种很好的内存管理机制,使得程序员在编写代码时不要显式的去释放自己使用的内存资源(这些在先前 ...

  2. C# using 三种使用方式 C#中托管与非托管 C#托管资源和非托管资源区别

    1.using指令.using + 命名空间名字,这样可以在程序中直接用命令空间中的类型,而不必指定类型的详细命名空间,类似于Java的import,这个功能也是最常用的,几乎每个cs的程序都会用到. ...

  3. C# 托管资源 与 非托管资源

    C# 托管资源 与 非托管资源 托管资源一般是指被CLR控制的内存资源,这些资源的管理可以由CLR来控制,.NET可以自动进行回收,主要是指托管堆上分配的内存资源.例如程序中分配的对象,作用域内的变量 ...

  4. 转/ C# 托管资源和非托管资源

    原文 对于这两个一直就是模模糊糊的,半知零解 托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,由.NET运行库在合适时调用垃圾回收器 ...

  5. C# 托管资源和非托管资源

    托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回 ...

  6. [转]在C#中使用托管资源和非托管资源的区别,以及怎样手动释放非托管资源:

    托管资源指的是.NET可以自动进行回收的资源,主要是指托管堆上分配的内存资源.托管资源的回收工作是不需要人工干预的,有.NET运行库在合适调用垃圾回收器进行回收. 非托管资源指的是.NET不知道如何回 ...

  7. .net 资源释放(托管资源和非托管资源)

    1.托管资源 像int.float.DateTime等都是托管资源:net中80%的资源都是托管资源: 托管资源的回收通过GC(垃圾回收器)自动释放分配给该对象的内存,但无法预测进行垃圾回收的时间,我 ...

  8. 托管DLL和非托管DLL的区别

    首先解释一下,托管DLL和非托管DLL的区别.狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件.非托管DLL不是在Dotnet环 境生成的DLL文件. 托管DLL文件,可以在Dotnet环境 ...

  9. .net托管资源与非托管资源

    在项目当中用到的资源分为托管资源和非托管资源,托管资源无非就是什么int.string.datatime之类,托管资源不需要人为去管理,.net framework中有专门针对托管资源的管理机制(GC ...

随机推荐

  1. 矩阵内积和Schur补

    > Many problems in the field of signal processing have been expended into matrix problems.So it's ...

  2. Qt窗口屏幕居中显示

    转自--> http://blog.chinaunix.net/uid-20718335-id-364404.html 窗口的屏幕居中显示问题,在各开发工具中原理相同,首先使用特定的方法得到显示 ...

  3. linux 软件包的命名规则

     linux软件包的命名规则 eg:主包       bind-9.7.1-1.el7.i586.rpm 子包 bind-libs-9.7.1-1.el7.i586.rpm bind-utils-9. ...

  4. Web前端理论知识记录

      Web前端理论知识记录 Elena· 5 个月前 cookies,sessionStorage和localStorage的区别? sessionStorage用于本地存储一个会话(session) ...

  5. php 设置页面导航动态active类样式的添加

    在用php制作项目中,一般都是把页头和页脚分离出来.页头导航在选中状态时会有一些样式,例如active等,当页面在首页时候,导航的首页也应该是active的样式,那么,怎么用php控制这些样式的添加和 ...

  6. 【python】关于函数递归使用 return 后,收到数据为 None。

    在写一个辗转相除求最小公因数的程序的时候,突然发现自己不管怎么写(除了两数恰巧可以整除),return 返回的值恒为 none. 代码为此: def gcd(a,b): if a%b==0: retu ...

  7. js事件绑定的几种方式与on()、bind()的区别

    版权声明:本文为博主原创文章,未经博主允许不得转载 一直不是很理解几种js事件绑定之间的区别与联系,今天百度了一下,在此做一总结: 1.如果只是简单的绑定一个事件,可以直接写在行内,点击执行一个函数, ...

  8. BEC listen and translation exercise 38

    很高兴看到有这么多人想了解我们的体育设施.It's good to see that there are so many people wanting to find out about our sp ...

  9. PS 滤镜——(扭曲)球面化 Spherize

    %%%% Spherize clc; clear all; close all; addpath('E:\PhotoShop Algortihm\Image Processing\PS Algorit ...

  10. CI中site_url和base_url的区别

    你若使用site_url("test/php/1");则实际url为 http://domain.com/index.php/test/php/1 若使用base_url(&quo ...