一、描述問題
當托管代碼呼叫非托管代碼的時候,經常會出現如下報錯:“嘗試讀取或寫入受保護的記憶體,這通常指示其他記憶體已損壞”,
二、原因分析
由于非托管代碼的記憶體指標的回收是由非托管代碼自身手動完成的,而不是像托管代碼一樣有統一的垃圾回識訓制,比如.NET的GC,
所以對于托管代碼的呼叫方來說無法控制其記憶體回收,以上問題的產生原因很可能是托管代碼呼叫了已經被回收的非托管物件,封裝
的好一點的非托管代碼一般都會有記憶體釋放的介面供外部呼叫,這樣呼叫方就可以管理非托管代碼的記憶體回收,
三、解決方法
盡量不用使用不確定的非托管代碼里面提供的物件,如果必須使用的話,實體化完成后直接使用而不要通過什么方法傳遞,委托回呼等方式來
獲取里面的物件,在這些復雜未知的程序中,很可能非托管的物件已經被回收了,
四、示例說明
當使用C#呼叫OpenCVSharp的時候,經常會出現以上問題,
錯誤代碼如下:
1、訂閱滑鼠回呼方法,并將mat的指標Data作為引數傳遞給回呼方法,
1 private void button15_Click(object sender, EventArgs e) 2 { 3 Mat mat = GetMat();//獲取Mat物件 4 Cv2.SetMouseCallback("輸入影像", GetRGBCvMouseCallback, mat.Data); 5 }
2、回呼方法,獲取每個點的RGB值
1 private void GetRGBCallbackMethod(MouseEvent @event, int x, int y, MouseEvent flags, IntPtr userdata) 2 { 3 switch (@event) 4 { 5 case MouseEvent.LButtonDown: 6 7 using (Mat mat = new Mat(Rows, Cols, _MatType, userdata))//這種方式會被記憶體回收,直接在這里面獲取物件 8 { 9 for (int i = 0; i < Rows; i++) 10 { 11 for (int j = 0; j < Cols; j++) 12 { 13 Vec3b s = mat.At<Vec3b>(j, i);//獲取第i0行第i1列) 這個方法會死 嘗試讀取收保護記憶體 14 } 15 16 } 17 } 18 break; 19 default: 20 break; 21 }
運行報錯,截圖如下:

正確代碼:
將7行代碼Mat mat = new Mat(Rows, Cols, _MatType, userdata)改成using (Mat mat=GetMat()) ,就不會出現以上問題,
原因分析:
原因很可能是userData中回呼的程序中已經被回收了,當再次使用時就會報嘗試訪問被保護的記憶體的錯誤,為了
防止此問題的發生,解決辦法就是重新實體化一個Mat物件,不使用可能被回收的userData資料,
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/96171.html
標籤:C#
下一篇:C# Replace字符替換函式
