原创文章,转载请注明出处!
接上文:http://www.cnblogs.com/yhlx125/archive/2011/11/22/2258543.html
博文的最后产生了问题:GC.Collect()显著的释放了内存,难道强制GC清理的效果这么明显?产生的内存增长不是因为COM对象、Mxd文件,而是托管的内存?
于是产生了这样的想法:MapClass、MapDocumentClass对象都是.Net托管对象,而非COM对象。事实是否如此呢?
IMapDocument pMapDoc = new MapDocumentClass();
int n = Marshal.ReleaseComObject(pMapDoc);
确实是执行了,返回值为0,说明正确释放了COM对象。如果执行下一段代码则第2句报错,说明.Net对象不能用Marshal.ReleaseComObject()方法来操作。
1 A pa = new A();
2 int m = Marshal.ReleaseComObject(pa);
3 MessageBox.Show(m.ToString());
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
class A
{
int a;
public int A1
{
get { return a; }
set { a = value; }
}
}
于是查找相关资料:学习了如下主题:
1. COM互操作性
2. Primary Interop Assemblies (PIAs,主互操作程序集),http://msdn.microsoft.com/zh-cn/library/aax7sdch.aspx
主互操作程序集是一个由供应商提供的唯一的程序集。它包含用 COM 实现的类型的类型定义(作为元数据)。 只能有一个主互操作程序集,而且该程序集必须由 COM 类型库的发行者用强名称签名。 一个主互操作程序集可以包装同一类型库的多个版本。
如果导入为程序集的 COM 类型库不是由原类型库的发行者签名的,该类型库不能作为主互操作程序集。 只有类型库的发行者才能产生真正的主互操作程序集。该程序集将成为用于与基础 COM 类型进行互操作的正式类型定义单元。
COM 组件的发行者生成主互操作程序集并将它们发布给开发人员以便在 .NET Framework 应用程序中使用。 对于发行者,本节提供有关产生主互操作程序集的信息。 对于开发人员,本节描述如何用主互操作程序集编程。
3. COM包装:http://msdn.microsoft.com/zh-cn/library/5dxz80y2.aspx
COM 包装(COM Wrapper)
运行时提供了包装类,使托管和非托管客户端认为它们是在其各自的环境中调用对象。 每当托管客户端对某个 COM 对象调用方法时,运行时就会创建一个运行时可调用包装 (RCW)。 RCW 的功能之一是抽取托管和非托管引用机制之间的差异。 运行时还会创建一个 COM 可调用包装 (CCW) 来逆转此过程,使 COM 客户端能够对 .NET 对象无缝地调用方法。 如下图所示,调用代码的性质将确定运行时所创建的包装类。
使用RCW,.NET客户程序就可以使用. Net对象而不是COM组件,所以不需要处理COM特性,这是由包装器来处理的。RCW隐藏了IUnknown接口和IDispatch接口并处理COM对象的引用数。(C#高级编程第六版 686页)
于是问题明了了,IMap pMap = new MapClass();这句代码使用的MapClass是Esri公司提供的PIAs表现形式,PIAs包含用 COM 实现的类型的类型定义(作为元数据)。 MapClass对象本身是.Net对象,实现了对COM对象Map的包装,即可认为传递了Map对象的引用。所以上文末尾产生的问题,调用GC.Collect()显著的释放了内存是因为释放了MapClass这个包装对象,而包装RCW对象是COM到.Net的桥梁,(数据封送处理是否可以视为产生了数据的副本?)Marshal.ReleaseComObject(pMapDoc);释放了COM对象但是没有释放托管的RCW,所以内存要等托管运行时释放。
(运行时所生成的标准 RCW 或 CCW 将为跨越 COM 和 .NET Framework 之间边界的调用提供充分的封送处理。)
ReleaseComObject 方法递减运行库可调用包装的引用计数。当引用计数达到零时,运行库将释放非托管 COM 对象上的所有引用(COM本身是自计数的)。