原创文章,转载请注明出处!

接上文: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());
View Code
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 类型进行互操作的正式类型定义单元。

对于开发人员,本节描述如何用主互操作程序集编程。

3. COM包装:http://msdn.microsoft.com/zh-cn/library/5dxz80y2.aspx

.Net环境下COM互操作COM 包装(COM Wrapper)

运行时提供了包装类,使托管和非托管客户端认为它们是在其各自的环境中调用对象。 如下图所示,调用代码的性质将确定运行时所创建的包装类。

使用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本身是自计数的)。

 

4.封送处理http://msdn.microsoft.com/zh-cn/library/9f9f3yxf.aspx

相关文章:

  • 2022-12-23
  • 2021-08-13
  • 2021-09-27
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-05-17
  • 2022-12-23
  • 2021-10-23
  • 2021-05-25
  • 2022-12-23
相关资源
相似解决方案