2014-10-28 79 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