关于用dispose释放内存释放专家的问题

1104人阅读
一. net的对象使用一般分为三种情况﹕
1.创建对象
2.使用对象
3.释放对象
二.创建对象
1.创建对象实际分为两个步骤﹕变量类型声明和初始化对象
2.变量类型声明(declare),如﹕
FileStream fs
这行代码会在当前的变量作用域空间(栈或堆)里建立一个叫做fs的变量﹐至少四个字节吧(因为要存一个对象的地址value)
3.初始化对象
对象在使用(调用其方法或属性)前﹐必须进行初始化。
fs = new FileStream(@&C:est.txt&,FileMode.OpenOrCreate);
这行代码会分成3个步骤﹕
a)在托管堆中分配一块内存﹐其大小等于FileStream中所有字段(当然不包括静态的)的内存总和加上MS认为需要的其它东东。
b)初始化对象的字段(值类型的把其位全部初始化成0,对象初始化为null﹐当然string是一个例外﹐它被初始化成空字符串)
c.调用FileStream相应的构造器﹐这里会初始化一个非托管资源(文件)的私有字段。
三.使用对象
使用对象就没什么讲的﹐就是调用对象的方法(或属性等)来完成某个功能当然为了释放对象而调用的方法应不属于此范畴(例如提到的Finalize等)
四.释放对象
1.释放对象也就是说这个对象我已经不需要了﹐现在我要把其释放﹐以便把其在堆上所占用的内存空间给收回来(当然变量名的内存空间就不需要管了﹐因为它会随其作用域自动消失)
2. .net自动进行内存管理﹐也就是说当它判断一个对象没有用了(当然有自己的算法)﹐它就会将其内存给自动收回来﹐但是其收回的时间一般不确定(当.net认为内存紧张时﹐它就会开始)
BTW:其实我们就是想自己收回对象的内存也不可能﹐因为MS没有提供途径(GC.Collect也是启动.net的内存收集功能)
五.第一个结论
在net中使用对象很简单﹐创建对象之后直接使用就可以了﹐不用了也不要去管它﹐垃圾收集器会帮你把内存要回来的。
当对象的成员引用了一个非托管资源时(不在托管堆上分配的内存或资源﹐像文件﹐数据库连接等等)﹐下面以一个例子来说明﹕
System.IO.FileStream类别﹐这是.net基本类库提供的一个非托管资源(文件)封装对象(用Reflector工具反编译mscorlib.dll可见其代码)
1.FileStream毫无疑问封装了一个非托管资源
观其源代码发现有这样一个私有成员﹕
private SafeFileHandle _通过构造器调用的Init方法可以发现这个成员的初始化代码﹕
this._handle = Win32Native.SafeCreateFile(
text2, num1, share, secAttrs, mode, num2,
Win32Native.NULL);
而后者实际上就是kernel32.dll中的CreateFile方法﹐它返回一个HANDLE(即非托管资源引用)
2.我们先来使用这个类别﹕
using S 
using System.IO;
public class TestFileStream
    public static void Main(string[] args)
    {
        //创建一个FileStream对象
        FileStream fs = new FileStream(@&C: est.txt&, FileMode.OpenOrCreate);
        Console.WriteLine(&您可以尝试在系统中删除c盘下的test.txt(回车键继续)&);
        //暂停程序执行﹐并尝试在系统中删除那个文件
        Console.ReadLine();
        //删除文件测试
        try
        {
            File.Delete(@&c: est.txt&);
        }
        catch (IOException ex)
        {
            Console.WriteLine(&[Error]程序删除文件失败﹕{0}&, ex.Message);
        }
    }
3.在程序挂起时(Console.ReadLine等待输入)﹐删除文件会失败﹐很容易理解﹐因为文件打开后没有将其关闭﹐系统不知道这个文件是否还有用﹐所以帮我们保护这个文件(理所当然﹐那个非托管资源所使用的内存还被程序占用着)
4.但是在程序执行完后﹐我们再尝试删除文件﹐成功﹗为什么?(fs不是没有关闭那个SafeFileHandle吗?)
当然您可以说﹐windows操作系统在一个进程结束后会自动回收其资源﹐没错【但是如果是com就惨了﹐因为com是存在于自己的独立进程内﹐而操作系统不负责这个:-( & 】﹐不过这里不是因为windows操作系统的功能﹐而是.net垃圾收集器帮的忙。
5.看下面这个例子
using System.IO;
public class TestFileStream
public static void Main(string[] args)
//创建一个FileStream对象
FileStream fs = new FileStream(@&C: est.txt&, FileMode.OpenOrCreate);
Console.WriteLine(&您可以尝试在系统中删除c盘下的test.txt(回车键继续)&);
//暂停程序执行﹐并尝试在系统中删除那个文件
Console.ReadLine();
/*进行垃圾收集*/
GC.Collect();
Console.WriteLine(&再删一下试试&);
Console.ReadLine();
}6.注意中间那行代码:
GC.Collect();
这是强制要.net垃圾收集器进行垃圾收集。
我们再去尝试删除test.txt﹐居然可以被删除了﹐为什么呀?(fs不是没有关闭那个SafeFileHandle吗?)﹐让我细细道来﹕
7.我们首先了解一下.net垃圾收集器进行垃圾收集的四种时机(参见﹕.net框架程序设计 李建忠译)
a.最常见的﹕当.net觉得合适时﹐例如它感到内存紧张了(朮语称为﹕0代对象充满)
b.微软强烈不建议使用的﹕GC的Collect方法调用(就是我们上面用的这种啦﹐因为会降低性能﹐会挂起进程, 等等﹐反正听微软的吧。当然某些时候可以用﹐就像我上面用来测试的代码﹐呵呵...)
c.应用程序域卸载时(AppDomain)
d.CLR被关闭时
8.现在我们可以明白第1个例子为什么在程序结束后文件可以被删除﹐因为CLR被关闭时,.net执行了垃圾收集(也就是等同于第二个例子的GC.Collect()代码)
9.所以现在所有的问题都集中到垃圾收集上面。它做了什么?
垃圾收集器在判断一个对象不会再被引用到后﹐就开始对它进行垃圾收集(即回收内存)清空内存(即把托管堆中的内存收回来)。
但是对象的有些字段引用到了非托管资源怎么办?如FileStream的_handle
所以我们必须告诉垃圾收集器﹐在你回收我的内存之前﹐先帮我执行一个方法来收回我的非托管资源﹐以免托管堆的内存被你回收了而引起我所引用的非托管资源的内存却被泄漏了。这个方法就是Finalize方法。它允许对象在垃圾回收器回收该对象使用的内存时适当清理其非托管资源。&默认情况下,Finalize&方法不执行任何操作。&如果您要让垃圾回收器在回收对象的内存之前对对象执行清理操作,您必须在类中重写Finalize&方法。
好了,我们现在知道是Finalize方法在起作用。下篇我们不仅要探讨如何使用一个封装了非托管资源的类(例如:FileStream),还将讨论如何自己实现一个包含非托管资源的类!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:266859次
积分:3551
积分:3551
排名:第7006名
原创:96篇
转载:27篇
评论:24条
(5)(5)(5)(6)(1)(1)(3)(1)(1)(3)(1)(1)(13)(6)(6)(1)(2)(1)(6)(3)(1)(5)(3)(1)(1)(1)(1)(4)(1)(2)(2)(1)(2)(5)(4)(2)(2)(5)(4)(1)(1)(1)(1)(5)(1)(1)(3)(2)(1)(7)(7)参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:41636次
排名:千里之外
原创:30篇
转载:102篇
(1)(2)(4)(10)(13)(3)(1)(3)(5)(7)(2)(2)(5)(3)(11)(4)(4)(8)(1)(1)(8)(26)(4)(2)(1)(1)谦虚若愚、求知如渴、不耻下问,持续进步...
互操作系列文章:
我们继续。前一篇文章中我们学习了基础知识中的DllImport关键特性;我们继续学习基础知识中的内存释放相关技术;
在托管与非托管内存之间,是不允许直接调用进行相互操作的,这点我相信稍微有点.NET技术基础的人都能了解;上一篇文章中有位朋友提出了些问题,刚好我们在这里就当是学习来粗略的分析一下,问题大概是这样的:
1.在.NET托管平台上的对象与非托管的对象之间是否能直接互换?
2.托管内存与非托管内存是否存在差异?如果存在差异是否有方法能进行等价转换或者叫做等价复制;
我们就上面两个问题来详细分析一下,由于本人也在学习这方面的知识所以理解的也不是很透彻,只能是一些微薄的猜测吧,大家一起来帮忙分析;
第一个问题:在.NET托管平台上的对象与非托管的对象之间是否能直接互换?其实第一个问题是隐藏在第二个问题里面的,首先我们要确定的是,&互换&与&转换&的概念,为了统一大家步伐,我们必须将&互换&与&转换&做一些定义;
&互换&:我假定有两块内存空间,每块内存空间存储不同的对象,比如:在一块非托管内存块中保存着Char*类型的指针,在另一块托管内存块中保存着String类型的值,由于Char*是指针类型,而我们的托管String是.NET平台类型,微小的变化就可能引起内存布局不同的可能;数据结构里面讲到,变量分为原子型和结构型,原子型变量都存在着字面值的概念,什么叫字面值就是我们人用来交流的数据值,比如:bool类型的true和false;两块内存中保存的东西是不一样的,高级语言在经历了一系列编译器处理之后,会确定下来内存中保存的数据是什么样子的;也就是说内存的分配原则是按照对象的类型来的;在托管与非托管的内存空间中,不同的平台所有的引用地址类型也各不相同,当然如果能成功的&互换&就说明能在托管与非托管之间进行直接数据访问了;总之互换是两个对象之间的彼此转换,是双向的;
&转换&:转换的概念我个人觉得来源于高级语言的语法解释而已,所谓转换其实也就是a到b的转换,将一种类型转换成另一种类型的动词描述,我们具体点打个比方:如果有一个对象是a,有一个对象是b,我想将a转换成b,就是将对象从一种状态转换成另一种状态;总之转换是单向的,只能是一种到另一种的转换;
针对上述我们分析的结果,由于时间比较紧,我们从第二个问题入手吧,因为本篇文章不是解决问题为主的;经过上面的分析我们确定托管内存与非托管内存的结构是不一样的,这种不一样并不是所有的对象类型都不一样,在.NET平台里面有一些如:int,char之类的平台等价类型,是可以直接互换的;如果是一些非等价类型,要想成功进行转换就必须得借助于托管对象关于互操作方面的知识了,由于这样一扯可能今天这篇文章是讲不完了,这里就粗略的过一下吧;我们下面进入今天的主题;其实有些概念真的不太好讲,你要说托管与非托管内存不一样,有人会问不一样在什么地方;真的没有说服性的理由;
关于非托管内存释放的问题
似乎今天的主题就是关于托管与非托管内存的问题,刚好能详细的说明上面的问题;要想在托管内存中释放非托管内存,没有那么简单;不同的代码库,调用的分配内存的方法不一样,算法也就不一样;C的分配与回收是malloc、free,C++的是new、delete,COM是CoTaskMemAlloc、CoTaskMemFree;在操作系统这么大的一个平台上存在着千千万万种内存操作方式,大家所熟悉的是上述几种,有可能那位技术牛人自己写了一套内存分配和回收的DLL,那么我们不可能让.NET一劳永逸,所以存在着这些不确定因素;(我穿插一句废话,其实不管我们所说的底层是什么样子的,哪怕真的越过了内核到了硬件抽象层甚至到了驱动部分,1就是1,2还是2,该走的路程还是会走,我们千万不要神秘话底层,只要我们抱着一颗探索的心什么都OK);:
.NET平台的默认内存分配和回收都是基于COM(组件对象模型)的,由于COM是一套非托管年代的公用原则,所以微软只能做到这个位置了;如果非托管内存是用COM的CoTaskMemAlloc分配的那么.NET的封送拆收器会自动的释放掉那块内存;如果是非托管内存是采用C的或者C++或者其他的什么方式分配的.NET根本不知道你是怎么分配的,所以这个时候需要我们采用折中的办法来解决。非托管的内存释放只有非托管知道,所以在非托管中定义一个释放非托管资源的方法,然后在用.NET平台去调用这个非托管方法来进行释放内存;下面我们来看一个小例子,以说明问题为主;
这是非托管的代码,由于时间关系我就没有写具体的操作了;说明原理就行了;
这是在托管.NET平台上面定义的非托管代码调用关系;
这样一来,不管非托管的内存是采用什么方法分配的内存我们都能在托管中将其释放;首要的原则就是我们必须清楚非托管内存的分配方法;如果不清楚的情况下,默认是COM的释放方法;:
阅读(...) 评论()> System.Drawing.Image释放内存的有关问题
System.Drawing.Image释放内存的有关问题
xujun2009 & &
发布时间: & &
浏览:16 & &
回复:1 & &
悬赏:0.0希赛币
System.Drawing.Image释放内存的问题如果代码这么写:
Image & image1 & = & new & Bitmap(filename1);
image1 & = & new & Bitmap(filename2);
执行到第二行,会不会把第一行在堆上分配的内存空间释放掉?要不要在中间加一句image1.Dispose()
一定要调用Dispose方法,或用using语句:
Image image1 = new Bitmap(filename1);
image1.Dispose();
image1 = new Bitmap(filename2); xujundong & &
00:45:21 & &
& & (0)(0)引用
本问题标题:
本问题地址:
温馨提示:本问答中心的任何言论仅代表发言者个人的观点,与希赛网立场无关。请对您的言论负责,遵守中华人民共和国有关法律、法规。如果您的言论违反希赛网问答中心的规则,将会被删除。
暂无合适的专家
&&&&&&&&&&&&&&&
希赛网 版权所有 & &&

我要回帖

更多关于 c 释放内存 的文章

 

随机推荐