2014-10-28 77 views
1

我有一種使用C++ DLL用佳能相機進行通信的應用,在該C++ DLL方法從C#應用程序調用。我在應用程序中看到的是,當拍照時,記憶會增加,當然。關閉「圖像捕捉窗口」後,應用程序仍會保留與所有圖像一樣的內存量。內存泄漏C++/C#應用

由於我的應用程序存在多層WPF UserControls,我認爲「圖像預覽UserControl」無法收集垃圾,因爲其他控件訂閱了從此控件觸發的事件。經過一番谷歌搜索之後,我決定對事件實施Weak Reference Pattern

//Source code found here: http://paulstovell.com/blog/weakevents 

public sealed class WeakEventHandler<TEventArgs> where TEventArgs : EventArgs 
    { 
     private readonly WeakReference _targetReference; 
     private readonly MethodInfo _method; 


     public WeakEventHandler(EventHandler<TEventArgs> callback) 
     { 
      _method = callback.Method; 
      _targetReference = new WeakReference(callback.Target, true); 
     } 

     public void Handler(object sender, TEventArgs eventArgs) 
     { 
      var target = _targetReference.Target; 
      if (target != null) 
      { 
       var callback = 
        (Action<object, TEventArgs>) 
         Delegate.CreateDelegate(typeof (Action<object, TEventArgs>), target, _method, true); 
       if (callback != null) 
       { 
        callback(sender, eventArgs); 
       } 
      } 
     } 
    } 

因此,如果我忘記取消訂閱一些活動,GC將收集它們。一些經過測試,這種方法沒有工作,所以我決定用Redgate ANTS Memory Profiler

我花了三年的快照:

  1. 拍攝圖像
  2. 之前,我花了後4個圖像
  3. 的破壞以後WPF的控制器比較快照1和3時

其結果是:

Piechart

enter image description here

正如你可以看到分配的非託管內存的量是很大的問題在這裏。我首先想到的是,當「圖像捕捉窗口」關閉時,C++ DLL不會釋放分配的內存。

我是正確的問題是在C++插件?我可以排除C#應用程序嗎?據我所知,所有用.NET編寫的代碼都是託管內存。

基於這裏的註釋是圖像從C++插件的C#插件如何到達:

從C++插件有這樣的回調:

_resultcallback(img->GetImageInfo().Data, img->GetImageInfo().Width, img->GetImageInfo().Height, img->GetImageInfo().BPP); 

而且方法其接收關於C#側的圖像:

private void OnResultImageCallback(IntPtr imagePtr, int width, int height, int bitsPerPixel) 
    { 
     _state = CameraState.InitializedStandby; 
     _cbResultData.Width = width; 
     _cbResultData.Height = height; 
     _cbResultData.BitsPerPixel = bitsPerPixel; 

     int memSize = bitsPerPixel * width * height/8; 
     _cbResultData.data = new byte[memSize]; 
     Marshal.Copy(imagePtr, _cbResultData.data, 0, memSize); 
     _deleteAllocatedImageFunction(imagePtr); 

     if (ImageCaptured != null) 
      ImageCaptured(_cbResultData.data, _cbResultData.Width, _cbResultData.Height, _cbResultData.BitsPerPixel); 

     _cbResultData.data = null; 
    } 

我也有以清除在我的C++,其TA所分配的存儲器的方法KES在字節指針這樣的:

BOOL CanonEDSDKWnd::ClearImageBuffer(BYTE* img) { 
    _debug->Write(_T("CanonEDSDKWnd::ClearImageBuffer")); 
    delete[] img; 
    return TRUE; 
} 

,其從與所述IntPtr從回調

_deleteAllocatedImageFunction(imagePtr)C#代碼調用;

+0

如何圖像到達從C C#代碼++圖書館?如何調用非託管方法?如何將圖像存儲在託管端?沒有關於代碼的知識,很難說任何有用的東西。 – 2014-10-28 08:31:14

+0

請參閱我的編輯。我認爲它應該是必不可少的部分。 – 2014-10-28 08:38:06

+0

我很確定回調中的'img'指向的對象必須以某種方式被釋放。你應該有一個C++函數來刪除img,並且在將數據複製到託管存儲之後應該調用它。 – 2014-10-28 08:47:05

回答

1

我覺得你的回調函數應如下所示:

C++方面:

_resultcallback(
    img     // extend the signature 
    img->GetImageInfo().Data, 
    img->GetImageInfo().Width, 
    img->GetImageInfo().Height, 
    img->GetImageInfo().BPP 
); 

C#的一面:

private void OnResultImageCallback(IntPtr img, IntPtr imagePtr, int width, int height, int bitsPerPixel) 
    { 
     _state = CameraState.InitializedStandby; 
     _cbResultData.Width = width; 
     _cbResultData.Height = height; 
     _cbResultData.BitsPerPixel = bitsPerPixel; 

     int memSize = bitsPerPixel * width * height/8; 
     _cbResultData.data = new byte[memSize]; 
     Marshal.Copy(imagePtr, _cbResultData.data, 0, memSize); 
     _deleteAllocatedImageFunction(img); 

     if (ImageCaptured != null) 
      ImageCaptured(_cbResultData.data, _cbResultData.Width, _cbResultData.Height, _cbResultData.BitsPerPixel); 

     _cbResultData.data = null; 
    } 
+0

我不認爲這會起作用,因爲'img'是'unique_ptr' – 2014-10-29 08:40:26