具有渐变的神秘Direct2D内存泄漏

时间:2017-12-18 20:34:02

标签: c# graphics memory-leaks directx direct2d

我有一个基于SharpDX的C#应用​​程序。有一种情况允许用户编辑线性渐变,但由于我没有找到修改ID2D1GradientStopCollection(又名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:创建+ 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的,   System.Collections.Specialized.NotifyCollectionChangedEventArgs)

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

1 个答案:

答案 0 :(得分:0)

错误发生在我创建渐变停止集合中: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();
}