NET+AE開發中常見幾種非託管對象的釋放

我們知道.Net中對於內存的管理有兩種方式,一種是託管對象管理,另一種是非託管對象管理。而我們通常理解的內存管理就是GC(垃圾收集),雖然GC通過對託管堆的管理,可以使我們有機會從繁鎖的諸如內存泄漏之類的問題中解放出來,可以將精力專注於程序的邏輯上。但是將所有的事情都交給GC有時會損及程序的效率,嚴重的甚至會導致錯誤。

爲什麼會出現這種情況呢?問題在於對非託管資源(文件句柄)或者需要特別關照的對象(Bitmap)對象等,GC表現得就有點差強人意了(這句話或許說得並不正確,因爲微軟設計GC的本意就是用來針對託管對象管理)。如何有效地利用GC來進行內存管理,如何對程序的性能進行優化不是本文討論的範圍。本文的要旨在於AE開發中如何來釋放非託管對象。

一、AOUninitialize.Shutdown.

很多時候我們都會遇到這種情況:在退出AE應用程序中,常常提示這樣的錯誤:“The instruction x references memory at x. The memory could not be read”。出現這種錯誤的原因主要在於COM對象(非託管對象)沒有釋放,在我們結束使用它的進程的時候,它阻止我們正常釋放它,它釋放的優先級高於當前使用它的進程釋放的優先級,也就是說進程釋放之前,必須先釋放掉它。

明白了上面的原理,那麼解決這一問題的方法便非常簡單,我們只需在應用程序退出之前調用ESRI.ArcGIS.ADF.COMSupport.AOUninitialize.Shutdown()方法即可釋放非託管對象了(9.2之前的版本AoUninitialize並不在ESRI.ArcGIS.ADF.COMSupport命名空間下,需注意)。

二、Marshal.ReleaseComObject

NET開發中,引用COM對象主要是通過RCW(Runtime Callable Wrappers)機制來實現的(有點類似於代理模式)。對於COM對象的釋放,GC表現得有點無能爲力,因此必須在程序中顯示釋放掉COM對象佔用的資源,否則將會出現一些意想不到的錯誤。比如重複地從Personal GeoDataBase中打開GeoDataBase Cursors而又沒有及時釋放,將會引發“No more tables can be opened.”其它情形中,你可能會發現應用程序退出時,COM對象依然在內存中引用。比如StyleGallery如果沒有顯示釋放,在應用程序退出時就會引發錯誤。

1、Releasing StyleGallery:

private void MyFunction() 
{
IStyleGallery styCls = new StyleGalleryClass() as IStyleGallery;
// Use the StyleGalleryClass here ...
int refsLeft = 0;
do
{
    refsLeft = Marshal.ReleaseComObject(styCls);
}
while (refsLeft > 0);
}
2、Releasing geodatabase cursors

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);
}
3、Releasing WebObject(ArcGIS Server)

private void doSomthing_Click(object sender, System.EventArgs e)
{
using (WebObject webobj = new WebObject())
{
    ServerConnection serverConn = new ServerConnection("doug", true);
    IServerObjectManager som = serverConn.ServerObjectManager;
    IServerContext ctx = som.CreateServerContext("Yellowstone","MapServer");
    IMapServer mapsrv = ctx.ServerObject as IMapServer;
    IMapServerObjects mapo = mapsrv as IMapServerObjects;
    IMap map = mapo.get_Map(mapsrv.DefaultMapName);
    IFeatureLayer flayer = map.get_Layer(0) as IFeatureLayer;
    IFeatureClass fclass = flayer.FeatureClass;
    IFeatureCursor fcursor = fclass.Search(null, true);
    webobj.ManageLifetime(fcursor);
    IFeature f = null;
    while ((f = fcursor.NextFeature()) != null)
    {
      // do something with the feature
    }
    ctx.ReleaseContext();
}
}
三、什麼時候應該釋放非託管對象?

這個問題非常重要,當我們確信在釋放之後不再調用非託管對象資源時候,就可以調用System.Runtime.InteropServices.Marshal.ReleaseComObject()方法進行顯式釋放了,否則將會引發新的錯誤。

總結:本文簡單的列舉了AE開發中幾種常見非託管對象的釋放問題,以供大家參考。有些方面說得不夠詳細,大家可以從ArcGIS Engine幫助中求得詳細資料。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章