神秘的Direct2D内存泄漏与渐变

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了神秘的Direct2D内存泄漏与渐变相关的知识,希望对你有一定的参考价值。

我有一个基于SharpDX的C#应用​​程序。有一种情况允许用户编辑线性渐变,但由于我没有找到修改ID2D1GradientStopCollection(aka SharpDX.Direct2D1.GradientStopCollection)的方法,我只是处理并重新创建用户调整偏移量的每一帧的渐变。渐变停止。

但是,我注意到如果我调整渐变停止足够的次数(即,在每秒重新创建60次线性渐变的同时将其拖动10秒钟),那么我注意到我的应用程序的内存使用量没有限制。我确定我在梯度上调用Dispose

private void RecreateBrush()
{

    var old = (SharpDX.Direct2D1.LinearGradientBrush)NativeBrush;
    NativeBrushLock.EnterWriteLock();

    NativeBrush = new SharpDX.Direct2D1.LinearGradientBrush(
        Target,
        new LinearGradientBrushProperties
        {
            StartPoint = new RawVector2(StartX, StartY),
            EndPoint = new RawVector2(EndX, EndY)
        },
        ConvertStops());

    old.GradientStopCollection.Dispose();
    old.Dispose();

    NativeBrushLock.ExitWriteLock();
}

但我的记忆力仍在继续增加。使用dotMemory对应用程序进行分析后发现,内存增加都是非托管内存,因此我开始深入挖掘,并使用DebugDiag 2.0来分析我的应用程序。 DebugDiag的分析指出d3d11!NOutermost::CDevice::CreateLayeredChild+15f是分配所有内存的罪魁祸首,其“泄漏概率”为100%。

这是什么意思,我如何摆脱内存泄漏?据我所知,我正在处理我正在创造的所有资源(ID2D1LinearGradientID2D1GradientStopCollection)。

这是我从WinDbg收集的堆栈跟踪:

d3d11!NOutermost :: CDevice :: CreateLayeredChild d3d11!CDevice :: CreateTexture2D_Worker + 0x47e d3d11!CDevice :: CreateTexture2D + 0xbf d2d1!CD3DDeviceCommon :: CreateTexture + 0x4c d2d1!CD3DSurface :: Create + 0xe1 d2d1!D2DGradientStopCollection :: EnsureRealizedForBrushType + 0x239 d2d1 !D2DGradientBrush :: SetGradientStopCollectionInternal + 0x85 D2D1!D2DLinearGradientBrush:创建+ 0x8c D2D1!的DrawingContext :: CreateLinearGradientBrush + 0xce D2D1!D2DDeviceContextBase :: CreateLinearGradientBrush + 0xe7 [托管到本机过渡] SharpDX.Direct2D1.RenderTarget.CreateLinearGradientBrush(SharpDX.Direct2D1.LinearGradientBrushProperties ,System.Nullable`1,SharpDX.Direct2D1.GradientStopCollection,SharpDX.Direct2D1.LinearGradientBrush)SharpDX.Direct2D1.LinearGradientBrush..ctor(SharpDX.Direct2D1.RenderTarget,SharpDX.Direct2D1.LinearGradientBrushProperties,SharpDX.Direct2D1.GradientStopCollection)MyApp.Direct2D。 LinearGradientBrush.RecreateBrush()MyApp.Direct2D.LinearGradientBrush.OnStopsChanged(System.Object,Syst em.Collections.Specialized.NotifyCollectionChangedEventArgs)

正如你所看到的,我确保处理画笔和渐变停止集合(当删除画笔时它似乎仍然存在)。但是,我的应用程序的本机内存使用量继续稳定增长,CLR垃圾收集器无法解释。

答案

错误发生在我创建渐变停止集合中:ConvertStops()产生一个SharpDX.Direct2D1.GradientStopCollection。但是,在调用LinearGradientBrush的构造函数之后,我需要确保处理该渐变停止集合,因为虽然返回的LinearGradientBrush具有表示指向同一值的指针的属性GradientStopCollection,但它不是同一个.NET实例。因此,通过从LinearGradientBrush.GradientStopCollection检索它来处置它不会将引用计数减少到0,并且数据继续存在。

修改后的RecreateBrush方法如下所示:

private void RecreateBrush()
{
    var old = (SharpDX.Direct2D1.LinearGradientBrush) NativeBrush;

    NativeBrushLock.EnterWriteLock();

    using (var nativeStops = ConvertStops())
        NativeBrush = new SharpDX.Direct2D1.LinearGradientBrush(
            Target,
            new LinearGradientBrushProperties
            {
                StartPoint = new RawVector2(StartX, StartY),
                EndPoint = new RawVector2(EndX, EndY)
            },
            nativeStops);

    old.Dispose();

    NativeBrushLock.ExitWriteLock();
}

以上是关于神秘的Direct2D内存泄漏与渐变的主要内容,如果未能解决你的问题,请参考以下文章

片段 - 全局视图变量与本地和内部类侦听器和内存泄漏

Direct2D 第4篇 渐变画刷

Python 和 MySQL 神秘的内存泄漏

自动释放池外的 NSString alloc 会造成神秘的内存泄漏?

在片段中保存活动实例:是否会导致内存泄漏?

Direct2D开发:向 MFC 项目添加 Direct2D 对象