C# 使用SuperMap控制項需要千萬注意的地方
討論SuperMap前,我們衷心的希望微軟能夠改進記憶體回收行程,更加智能的協助開發人員釋放對象。 首先看下傳統的COM對象與.NET架構物件模型的建立與釋放的不同: (1)、COM對象的客戶必須自己管理COM對象的生存期,而.NET對象的生存期由CLR(Common Language Runtime)來管理,即通過GC(Garbage Collection)機制自動回收。 (2)、COM對象的客戶通過指標引用COM對象,對象在記憶體中的位置是不變的,而.NET對象在記憶體中的駐留由.NET架構執行環境(execution environment)來管理,對象在記憶體中的位置是可變的,比如出於最佳化效能的考慮,同時會更新所有對對象的引用。這一點也是以CLR中不使用指標為前提的。 簡單的說.com客戶每次引用對象的時候,就調用 IUnKnown->AddRef(),而每次釋放對象的時候,就調用 IUnKnown->Release(),一旦引用計數達到零,就釋放執行個體。 如何在.NET中Release徹底釋放呢?非常幸運,在.net中允許程式員顯式地自己調用com的Release方法,這個方法叫做System.Runtime.InteropServices.Marshal.ReleaseComObject。 現在來說SuperMap,根本上講SuperMap的控制項在.NET中都是COM對象,這次我們討論的要點就是如何寫才能完全徹底的釋放COM對象。先來看段代碼: private void axSuperMap1_Tracked(object sender, EventArgs e) { soDatasetVector _soDatasetVector = SuperWorkspace.Datasources[0].Datasets[0] as soDatasetVector; soRecordset _soRecordset = _soDatasetVector.Query("1=2", true, null, ""); if (_soRecordset.AddNew(axSuperMap1.TrackedGeometry, null) == -1) { MessageBox.Show("添加資料失敗"); } System.Runtime.InteropServices.Marshal.ReleaseComObject(_soRecordset); _soRecordset = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDatasetVector); _soDatasetVector = null; } 這段代碼看似相當的簡潔 風格很棒。但是實際上卻沒有釋放完全。 現在我們就來說標題上的“千萬千萬”的地方。 對於一些隱含返回的對象,也要這樣調用ReleaseComObject才能將其正確釋放,並保證其正常運作。 對於一些隱含返回的對象,也要這樣調用ReleaseComObject才能將其正確釋放,並保證其正常運作。 對於一些隱含返回的對象,也要這樣調用ReleaseComObject才能將其正確釋放,並保證其正常運作。 現在我們來看看上面這段代碼的釋放完全的寫法: private void axSuperMap1_Tracked(object sender, EventArgs e) { soDataSources _soDataSources = SuperWorkspace.Datasources; soDataSource _soDataSource = SuperWorkspace.Datasources[0]; soDatasets _soDatasets=_soDataSource.Datasets; soDataset _Dataset = _soDatasets[0]; soDatasetVector _soDatasetVector = _Dataset as soDatasetVector; soGeometry _soGeometry = axSuperMap1.TrackedGeometry; soRecordset _soRecordset = _soDatasetVector.Query("1=2", true, null, ""); if (_soRecordset.AddNew(_soGeometry, null) == -1) { MessageBox.Show("添加資料失敗"); } System.Runtime.InteropServices.Marshal.ReleaseComObject(_soGeometry); _soGeometry = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(_soRecordset); _soRecordset = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDatasetVector); _soDatasetVector = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(_Dataset); _Dataset = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDatasets); _soDatasets = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDataSource); _soDataSource = null; System.Runtime.InteropServices.Marshal.ReleaseComObject(_soDataSources); _soDataSources = null; } 你沒看錯,其實我也很鬱悶。這樣寫的確很弱,很委瑣。 但是千萬記住,如果不想你寫的產品在你想不到的時候彈出“System.AccessViolationException: 嘗試讀取或寫入受保護的記憶體。這通常指示其他記憶體已損壞。”的錯誤,還是老實再老實的用這很弱的寫法吧。 |
轉載自http://www.gisbox.cn/thread-156-1-1.html