带有梯度的神秘Direct2D内存泄漏 [英] Mysterious Direct2D Memory Leak with gradients

查看:117
本文介绍了带有梯度的神秘Direct2D内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个基于SharpDX的C#应用​​程序.在某些情况下,允许用户编辑线性渐变,但是由于我没有找到修改 ID2D1GradientStopCollection (又称为 SharpDX.Direct2D1.GradientStopCollection )的方法,我只是在为用户调整渐变光阑的偏移量的每一帧设置并重新创建渐变.

I have a C# application based on SharpDX. There is a scenario in which the user is allowed to edit linear gradients, but since I did not find a way to modify an ID2D1GradientStopCollection (a.k.a. SharpDX.Direct2D1.GradientStopCollection), I am simply disposing and recreating the gradient for every frame that the user adjusts the offset of a gradient stop.

但是,我注意到,如果我将渐变停止调整了足够的次数(即,在每秒重新创建线性渐变60次的同时将其拖移10秒钟),那么我注意到我的应用程序的内存使用不受限制地增加了.我确定我正在渐变上调用 Dispose :

However, I noticed that if I adjust the gradient stop enough times (i.e., drag it around for 10 seconds while the linear gradient is recreated 60 times per second), then I notice that the memory usage of my application balloons without bound. I am certain that I am calling Dispose on the gradient:

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%.

But my memory usage still continues to increase. Profiling the application with dotMemory reveals that the memory increase is all unmanaged memory, so I began to dig deeper, and used DebugDiag 2.0 to profile my application. DebugDiag's analysis pointed at d3d11!NOutermost::CDevice::CreateLayeredChild+15f as the culprit that was allocating all of that memory, with a "Leak Probability" of 100%.

这是什么意思,如何消除内存泄漏?据我所知,我正在处理正在创建的所有资源( ID2D1LinearGradient ID2D1GradientStopCollection ).

What does this mean, and how do I get rid of the memory leak? As far as I can tell, I am disposing of all of the resources I am creating (the ID2D1LinearGradient and the ID2D1GradientStopCollection).

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

This is the stack trace that I gathered from WinDbg:

d3d11!最无:: CDevice :: CreateLayeredChildd3d11!CDevice :: CreateTexture2D_Worker + 0x47ed3d11!CDevice :: CreateTexture2D + 0xbfd2d1!CD3DDeviceCommon :: CreateTexture + 0x4cd2d1!CD3DSurface :: Create + 0xe1d2d1!D2DGradientStopCollection :: EnsureRealizedForBrushType + 0x239d2d1!D2DGradientBrush :: SetGradientStopCollectionInternal + 0x85d2d1!D2DLinearGradientBrush :: Create + 0x8cd2d1!DrawingContext :: CreateLinearGradientBrush + 0xced2d1!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)

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::Create+0x8c d2d1!DrawingContext::CreateLinearGradientBrush+0xce d2d1!D2DDeviceContextBase::CreateLinearGradientBrush+0xe7 [Managed to Native Transition] 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垃圾回收器来说是无法接受的.

As you can see, I make sure to dispose of both the brush and the gradient stop collection (which seems to continue to exist when the brush is deleted). However, the native memory usage of my application continues to steadily increase, unclaimable by the CLR garbage collector.

推荐答案

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

The error was in my creation of the gradient stop collection: ConvertStops() yields a SharpDX.Direct2D1.GradientStopCollection. However, I need to make sure dispose of that gradient stop collection after calling the constructor of LinearGradientBrush, because while the returned LinearGradientBrush has a property GradientStopCollection that represents a pointer to the same value, it is not the same .NET instance. Therefore, disposing of it by retrieving it from the LinearGradientBrush.GradientStopCollection does not decrease the reference count to 0, and the data continues to exist.

修改后的 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内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆