C ++ / C#应用程序中的内存泄漏

时间:2014-10-28 08:18:17

标签: c# c++ wpf ant memory-leaks

我有一个使用C ++ DLL与Canon Camera通信的应用程序,这个C ++ DLL中的方法是从C#应用程序调用的。我在应用程序中看到的是,在拍照时,内存会增加。关闭"图像捕获窗口"当捕获所有图像时,应用程序仍保持与其相同的内存量。

由于我的应用程序存在多层WPF UserControls,我认为" Image Preview 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控制器后
  4. 比较快照1和3时的结果:

    Piechart

    enter image description here

    正如您所看到的,分配的非托管内存量是一个大问题。我的第一个想法是,当&#34;图像捕获窗口&#34;时,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 ++中已分配的内存,它接受一个像这样的字节指针:

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

    使用回调中的IntPtr从C#代码调用

    _deleteAllocatedImageFunction(imagePtr);

1 个答案:

答案 0 :(得分: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; 
    }