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

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

我有一个使用 C++ DLL 与佳能相机通信的应用程序,此 C++ DLL 中的方法是从 C# 应用程序调用的。我在应用程序中看到的是,当拍照时,内存当然会增加。在我关闭“Image Capture Window”后,应用程序仍然拥有与捕获所有图像时相同的内存量。

由于我的应用程序存在多层 WPF 用户控件,我认为“图像预览用户控件”无法进行垃圾回收,因为其他控件订阅了从该控件触发的事件。经过一番谷歌搜索后,我决定对事件实现弱引用模式

 //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 Controller 销毁后

比较快照 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++ 中分配的内存,它采用这样的字节指针:

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

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

_deleteAllocatedImageFunction(imagePtr);

最佳答案

我认为你的回调函数应该如下所示:

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; 
    }

关于c# - C++/C# 应用程序中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26603595/

相关文章:

c++ - 在 xcode ".mm"文件中设置一个 c++ 类 nil。

c# - 如何绑定(bind)一个简单的数组?

c# - WPF ListView 列标题两侧显示白线

c# - 如何使用 SQL Select 语句结果填充 ArrayList

C# 正则表达式删除特殊字符但保留字母数字

c++ - 如何将接口(interface)对象转换为特定的继承对象

C++ 返回 stringstream.str()

wpf - 如何覆盖全局样式(没有 x :Key), 或将命名样式应用于所有类型目标控件?

c# - 等待所有线程完成,超时

c# - 动态更改对象的命名空间