.NET简谈互操作(四:基础知识之Dispose非托管内存)
互操作系列文章:
-
.NET简谈互操作(一:开篇介绍)
-
.NET简谈互操作(二:先睹为快)
-
.NET简谈互操作(三:基础知识之DllImport特性)
-
.NET简谈互操作(四:基础知识之Dispose非托管内存)
-
.NET简谈互操作(五:基础知识之Dynamic平台调用)
-
.NET简谈互操作(六:基础知识之提升平台调用性能)
-
.NET简谈互操作(七:数据封送之介绍)
我们继续.NET互操作学习。前一篇文章中我们学习了基础知识中的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平台去调用这个非托管方法来进行释放内存;下面我们来看一个小例子,以说明问题为主;
图1:
这是非托管的代码,由于时间关系我就没有写具体的操作了;说明原理就行了;
图2:
这是在托管.NET平台上面定义的非托管代码调用关系;
图3:
这样一来,不管非托管的内存是采用什么方法分配的内存我们都能在托管中将其释放;首要的原则就是我们必须清楚非托管内存的分配方法;如果不清楚的情况下,默认是COM的释放方法;:[王清培版权所有,转载请给出署名]