ArcObjects帮助文档翻译--释放COM对象 Releasing COM references

释放COM对象

原文链接:http://resources.arcgis.com/en/help/arcobjects-net/conceptualhelp/#/Releasing_COM_references/0001000004tm000000/

AOUninitialize.Shutdown

当一个独立的engine程序关闭时有可能会出现未知的错误。比如当关闭一个带打开着的地图文档的mapcontrol时可能会报出类似这样的错误:

The instruction x references memory at x. The memory could not be read.

原因有可能是有些COM对象还在内存中,造成了进程结束时COM对象库试图终止引用时的错误。为了预防这种错误,ESRI.ArcGIS.ADF.Local中加入了一个static的shutdown方法。这个方法可以确保进程结束前,所有未使用的COM引用都已经被卸载了。

 private void Form1_Disposed(object sender, System.EventArgs e)

{

   ESRI.ArcGIS.ADF.COMSupport.AOUninitialize.Shutdown();

}

 

这个方法只对于已经没有COM对象存在的时候适用,比如把它放在

engine程序的Form Disposed事件中。

 

ComReleaser类

虽然AOUninitialize.Shutdown能够处理很多关闭程序时的问题,尤其是当有engine控件的情况下,但有的时候还是会有内存中有COM对象没释放造成的问题,这时可以用在ESRI.ArcGIS.ADF.Connection.Local.dll中的ComReleaser类。这个类实际上用的是System.Runtime.InteropServices.Marshal.ReleaseCOMObject方法来释放指向COM对象的引用。需要注意的是这个方法只有在这个COM对象在程序中已经完全不需要用到的情况下才能够使用。

 

 

Marshal.ReleaseComObject

在.net里COM对象的引用是由RCW是来管理的,这些对象被当做是底层COM对象的代理对象来处理。.net的垃圾回收机制负责把不用的对象从内存中清除,但是这种机制我们控制不了,也就是垃圾回收的时间点是不一定的。这样一来有的时候一些系统资源,如文件处理、数据库连接等就需要手动来从内存中释放。

 

如果对象释放的不正确那么有可能会造成各种错误,比如:频繁的打开个人地理数据的指针但是不去确保上一个指针已经被释放,那么就有可能报无法打开表的错误:no more tables can be opened. 另外程序关闭的时候如果有未释放的内存对象也有可能会报错,比如StyleGallery.这时就可以使用System.Runtime.InteropServices.Marshal.ReleaseCOMObject方法来强制释放。

 

调用这个方法后,RCW中该对象的引用数就会减1,当引用数减到0的时候(有可能需要反复调用ReleaseCOMObject方法)RCW就会把这个对象标记为需要垃圾回收的对象,如果其底层的COM对象也没有其他的引用了的话,那么RCW就会把底层的COM对象也清除掉。

 

使用ReleaseComObject方法会对当前进程中所有的引用都起作用,尤其是当从加载到Desktop里的dll中调用这个方法时需要特别小心。千万不要调用这个方法,如果有可能有其他任何引用还指向要被释放的对象。比如如果对MxDocument使用了这个方法,那么程序中其他的地方都不能访问MxDocument这个对象了。如果是独立的engine程序的话那么对释放对象的控制会更加灵活和准确。

 

下面这个示例就是如何对StyleGallery使用ReleaseComObject 方法。代码中重复使用ReleaseComObject直到StyleGallery的引用数减为0,也就是没有任何对象引用指向StyleGallery了。只有当你确定不会有地方需要引用到某个对象时再这么做。

private void MyFunction()
{
    ESRI.ArcGIS.Display.IStyleGallery styCls = new
        ESRI.ArcGIS.Framework.StyleGalleryClass()as
        ESRI.ArcGIS.Display.IStyleGallery;
    // Use the StyleGalleryClass here.
    int refsLeft = 0;
    do
    {
        refsLeft = Marshal.ReleaseComObject(styCls);
    }
    while (refsLeft > 0);
}

另外在循环中也可以调用ReleaseComObject 方法,比如在使用迭代器enumerator时,这样就可以主动的来释放对象而不用等着RCW的垃圾回收机制不定时的清理内存了。这种方式特别适用于使用指针、地理数据库对象、符号库和其他会hold住系统资源的情况。

 

Releasing geodatabase cursors释放地理数据库指针

有一些对象会占用或者锁定资源,直到它们被销毁时资源才被释放。比如当使用地理数据库指针时,它就会对要素类或者表加上共享锁sharedlock。在被上了共享锁的情况下,其他客户端可以访问、查询或者更新被锁住的表,但是却不能够删除表或者更改表结构。使用更新指针Updatecursor会给表加上排它锁exclusivelock,这样其他的客户端连访问也访问不了了。这些锁会导致数据对于其他客户端来说是不可用的,直到所有数据库指针的引用都已经被释放了。

 

对SDE数据源来说,每个指针会hold住一个SDE流,如果SDE有多个客户端访问的话,那么每个客户端都会hold着SDE流,直到达到上限为止。达到上限后再有其他的客户端要访问SDE的话就访问不了了,而且服务器的资源也可能会不够用了。在.net中只有指针被垃圾回收后资源才会被释放掉。所以如果对数据库进行了多次会锁住资源的操作后,有可能就会报各种错,比如资源不足等。

 

例如对个人地理数据库操作后可能会报数据库只允许有最多255个连接的错误。甚至有的时候可能报的错毫无头绪,跟资源占用都没有关系。

 

调用GC.Collect方法可以在想要的时间点初始化垃圾回收机制。但是最好不要强制执行垃圾回收,因为一个是可能会很慢,一个是会影响到最优化的垃圾回收机制。

 

正确的方式应该是使用Marshal.ReleaseComObject来释放对象。使用完cursor后都要做释放,比如IFeatureCursor,ISet和数据库迭代器。再次强调,不要释放有可能在程序里其他地方会用到的对象,比如不是你创建创建的对象。

不管是在web程序中还desktop、engine程序中,如果指着垃圾回收机制完成所有的释放工作那么有可能就会报错,该释放的就得主动释放。

 

ArcGIS for Desktop andArcGIS Engine

使用cursor后释放的示例:

 for (int i = 1; i < 2500; i++)
{
    IQueryFilter qu = New QueryFilterClass();
    qu.WhereClause = @"Area = " + i.ToString();
    IFeatureCursor featCursor = featClass.Search(qu, true);
    // Use the feature cursor as required.
    System.Runtime.InteropServices.Marshal.ReleaseComObject(featCursor);
}

ArcGIS Engine

在engine程序中如果使用了单一实例的类Singletons,那么释放就更加重要了。Singletons就是在一个进程中只能有一个实例存在的类。如果有singletons被挂起了(pinning)那么程序在关闭时就会报错。不管用什么API, 在用完singleton以后必须要进行释放。非.net的话把变量设为空即可,.net中的话就要用ComReleaser。

 

Server略

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值