Net下Arcgis engine COM对象的释放问题

来源:互联网 发布:诲女知之乎单独翻译 编辑:程序博客网 时间:2024/06/03 19:39

问题描述:

       最近的项目中涉及到离线编辑的问题,我的做法是根据业务需求在本地建一个FileGeodatabase数据库,在编辑过程中需要重新同步数据库时候,需要删除现有离线数据库,但是即使使用了System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o),在删除数据库的时候,任然提示数据库文件被另外一个线程占用。

问题分析:

        ArcObject.Net是在COM的基础上构建的, 因而客户只能在RCWs 的基础上进行COM组件的调用,COM对象是分配在非托管堆上的,因而GC无法管理其生命周期,这也会造成一些某名奇妙的问题,比如资源无法释放的问题。根据AO的开发文档,我们可以使用ComRelease来管理这些非托管资源,使用.net reflector看了一下ComReleaser的实现(AO 10.1中ComReleaser的实现在ESRI.ArcGIS.ADF.Connection.Local中),具体如下:


public class ComReleaser : IDisposable{// Fieldsprivate ArrayList m_array;// Methodspublic ComReleaser();public void Dispose();protected virtual void Dispose(bool disposing);protected override void Finalize();public void ManageLifetime(object o);public static void ReleaseCOMObject(object o);}


从上面的代码中可以看出ComReleaser是实现了IDispose接口的对象,因而可以直接使用using来管理其生命周期,这个对象的功能的关键功能就是释放COM对象,打开他的Dispose方可以看到,其实他是循环调用RelaseComObject来减少对象链表中RCWs的引用计数,根据MSDN的问题,这一功能其实可以直接使用FinalReleaseComObject来实现,因而可以使用如下方式来实现同样的功能:

public static void ReleaseCom(object o){try{System.Runtime.InteropServices.Marshal.FinalReleaseComObject(o);}catch { }finally{o = null;}}


     然而!!!!!这样并没用卵用,在进行删除离线数据库的时候,发现离线数据库文件无法删除,出现进程占用的问题,逐层排查,可以断定原因在于在数据同步功能块,资源没有正确释放,因而我采用如下方式进行释放:

public void Synchronization(IPolygon updateExtent){_updatePolygon = updateExtent;if (_updatePolygon == null) return;IMapDocument masterDoc = new MapDocumentClass();masterDoc.Open(_masterGeoDataBase);IMapDocument offlineDoc = new MapDocumentClass();offlineDoc.Open(_offlineGeoDataBase);IMap onlyOfflineMap = offlineDoc.get_Map(0);IMap onlyMasterMap = masterDoc.get_Map(0);for (int offlineLayerIndex = 0; offlineLayerIndex < onlyOfflineMap.LayerCount;++offlineLayerIndex){ILayer curOfflineLayer = onlyOfflineMap.get_Layer(offlineLayerIndex);string curLayerName = curOfflineLayer.Name;ILayer masterLayer = Utility.GetLayerByName(curLayerName, onlyMasterMap);UpdateForDelete(masterLayer, curOfflineLayer);UpdateForNewOrModify(masterLayer, curOfflineLayer);Utility.ReleaseCom(curOfflineLayer);Utility.ReleaseCom(masterLayer);}offlineDoc.Save();masterDoc.Save();offlineDoc.Close();masterDoc.Close();Utility.ReleaseCom(offlineDoc);Utility.ReleaseCom(masterDoc);Utility.ReleaseCom(onlyOfflineMap);Utility.ReleaseCom(onlyMasterMap);}


  满怀高兴的F5,BUG依然,好想召唤我无所不能的大圣。难道是还有资源没有释放?找遍代码也没找到,只能Google了,找到两篇博客http://blog.csdn.net/lion_wing/article/details/4429179 和http://www.cnblogs.com/tendzzss/archive/2011/11/11/2245627.html ,第二篇文章进行了详细案例测试,得出了不同的应用场景,第一篇博中提到的一句话读自己的帮助很大,RCW是由GC 管理,在垃圾收集的时候会将该对象置于Finalize队列,由GC调用其析构函数,释放COM对象,《精通.Net互操作》一书中也提到了,RCW会保持非托管资源的引用直至运行库对包装执行垃圾回收,但是GC是不确定,那么按照这个意思,清完计数后,我直接GC.Collect()强制进行垃圾回收,是不是就能完全释放COM对象了,然后,然后,程序完美通过。


有什么不妥之处,欢迎交流:E-mai:zhaozhipeng1000@126.com ; QQ 群: 191593647

0 0
原创粉丝点击