Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/281.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# SharpDX内存碎片_C#_Memory_Directx 9_Sharpdx_Memory Fragmentation - Fatal编程技术网

C# SharpDX内存碎片

C# SharpDX内存碎片,c#,memory,directx-9,sharpdx,memory-fragmentation,C#,Memory,Directx 9,Sharpdx,Memory Fragmentation,我正在开发一个.NET3.5应用程序,它使用SharpDX渲染平铺2D图像 纹理(Texture2D)按需加载到缓存中,并在托管池中创建 当不再需要纹理时,纹理将被丢弃,我已验证是否正确调用了Dispose()。SharpDX对象跟踪表示没有最终确定的纹理 问题是,纹理使用的大量非托管堆内存在处置后仍会保留。加载新纹理时会重用此内存,因此不会泄漏内存 然而,应用程序的另一部分也需要大量内存来处理新图像。因为这些堆仍然存在,即使纹理已被处理,也没有足够的连续内存来加载另一个图像(可能是数百MB)

我正在开发一个.NET3.5应用程序,它使用SharpDX渲染平铺2D图像

纹理(Texture2D)按需加载到缓存中,并在托管池中创建

当不再需要纹理时,纹理将被丢弃,我已验证是否正确调用了Dispose()。SharpDX对象跟踪表示没有最终确定的纹理

问题是,纹理使用的大量非托管堆内存在处置后仍会保留。加载新纹理时会重用此内存,因此不会泄漏内存

然而,应用程序的另一部分也需要大量内存来处理新图像。因为这些堆仍然存在,即使纹理已被处理,也没有足够的连续内存来加载另一个图像(可能是数百MB)

如果我使用
AllocHGlobal
分配非托管meory,则结果 调用
FreeHGlobal
后,堆内存再次完全消失

VMMap显示大量使用应用程序后的非托管堆(红色)

我们可以在这里看到,非托管堆占用了约380MB的内存,尽管此时实际提交的内存只有约20MB

从长远来看,应用程序正在被移植到64位。但是,由于非托管依赖关系,这并非微不足道。此外,并非所有用户都在64位计算机上

编辑:我已经对这个问题进行了演示-创建WinForms应用程序并通过Nuget安装SharpDX 2.6.3

Form1.cs:

using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Forms;
using SharpDX.Direct3D9;

namespace SharpDXRepro {
    public partial class Form1 : Form {
        private readonly SharpDXRenderer renderer;
        private readonly List<Texture> textures = new List<Texture>();

        public Form1() {
            InitializeComponent();

            renderer = new SharpDXRenderer(this);

            Debugger.Break(); // Check VMMap here

            LoadTextures();

            Debugger.Break(); // Check VMMap here

            DisposeAllTextures();

            Debugger.Break(); // Check VMMap here

            renderer.Dispose();

            Debugger.Break(); // Check VMMap here
        }

        private void LoadTextures() {
            for (int i = 0; i < 1000; i++) {
                textures.Add(renderer.LoadTextureFromFile(@"D:\Image256x256.jpg"));
            }
        }

        private void DisposeAllTextures() {
            foreach (var texture in textures.ToArray()) {
                texture.Dispose();
                textures.Remove(texture);
            }
        }
    }
}
using System;
using System.Linq;
using System.Windows.Forms;
using SharpDX.Direct3D9;

namespace SharpDXRepro {
    public class SharpDXRenderer : IDisposable {
        private readonly Control parentControl;

        private Direct3D direct3d;
        private Device device;
        private DeviceType deviceType = DeviceType.Hardware;
        private PresentParameters presentParameters;
        private CreateFlags createFlags = CreateFlags.HardwareVertexProcessing | CreateFlags.Multithreaded;

        public SharpDXRenderer(Control parentControl) {
            this.parentControl = parentControl;

            InitialiseDevice();
        }

        public void InitialiseDevice() {
            direct3d = new Direct3D();
            AdapterInformation defaultAdapter = direct3d.Adapters.First();

            presentParameters = new PresentParameters {
                Windowed = true,
                EnableAutoDepthStencil = true,
                AutoDepthStencilFormat = Format.D16,
                SwapEffect = SwapEffect.Discard,
                PresentationInterval = PresentInterval.One,
                BackBufferWidth = parentControl.ClientSize.Width,
                BackBufferHeight = parentControl.ClientSize.Height,
                BackBufferCount = 1,
                BackBufferFormat = defaultAdapter.CurrentDisplayMode.Format,
            };

            device = new Device(direct3d, direct3d.Adapters[0].Adapter, deviceType,
                parentControl.Handle, createFlags, presentParameters);
        }

        public Texture LoadTextureFromFile(string filename) {
            using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
                return Texture.FromStream(device, stream, 0, 0, 1, Usage.None, Format.Unknown, Pool.Managed, Filter.Point, Filter.None, 0);
            }
        }

        public void Dispose() {
            if (device != null) {
                device.Dispose();
                device = null;
            }

            if (direct3d != null) {
                direct3d.Dispose();
                direct3d = null;
            }
        }
    }
}

我的问题是,(如何)在纹理被处理之后,我可以回收这些非托管堆消耗的内存吗?< /P> < P>看来,由英伟达驱动程序分配的内存似乎是分配的。据我所知,所有的释放方法都被正确调用,所以这可能是驱动程序中的一个bug。环顾互联网,会发现一些似乎与此相关的问题,尽管这些问题并不严重,值得参考。我无法在ATi卡上测试这一点(我已经有十年没见过了:D)

看来你的选择是:

  • 确保你的纹理足够大,永远不会被分配到“共享”堆上。这使得内存泄漏的速度慢得多——尽管它仍然是未释放的内存,但它不会导致内存碎片的严重程度接近您所经历的程度。您正在谈论绘制瓷砖-这在历史上一直是使用瓷砖集来完成的,它提供了更好的处理(尽管它们也有缺点)。在我的测试中,简单地避免微小的纹理几乎消除了这个问题——很难判断它是隐藏的还是完全消失了(两者都是很有可能的)
  • 在单独的流程中处理您的处理。您的主应用程序将在需要时启动另一个进程,当辅助进程退出时,内存将被正确回收。当然,这只有在您编写一些处理应用程序时才有意义——如果您正在制作一些实际显示纹理的东西,这不会有任何帮助(或者至少设置起来会非常棘手)
  • 不要处理纹理
    Managed
    texture pool为您处理纹理在设备之间的分页,甚至允许您使用优先级等,以及刷新整个设备(托管)内存。这意味着纹理将保留在进程内存中,但与当前方法相比,您似乎仍能获得更好的内存使用率:)
  • 这些问题可能仅与DirectX 9上下文有关。您可能希望使用较新的接口之一进行测试,如DX10或DXGI。这并不一定限制您使用DX10+GPU,但您将失去对Windows XP的支持(无论如何,Windows XP不再受支持)

如何加载纹理?
Texture-Texture=Texture.FromStream(设备、流、0、0、1、用法、无、格式、未知、池、托管、过滤器、点、过滤器、无、0)其中流当前始终是一个MemoryStream。我添加了一个简化的代码示例,该示例再现了该问题。这可能不会让您满意,但对我来说不会重现。我使用的是SharpDX的最新租赁前版本,我使用的是Windows7(使用NvidiaQuadro)。只要执行
DisposeAllTextures
,所有非托管VM都将消失。此外,我在调试器之外运行代码——这可能也会有所不同。任何响应都会让我感到高兴!谢谢你尝试一下。我使用的是Windows 8.1和Quadro NVS 315。我可以在调试器之外使用发布版本进行复制。实际的应用程序在Windows7上做同样的事情,使用其他各种Quadro卡。所以也许SharpDX在这里是最受欢迎的-你使用了3.0.0-alpha02吗?如果是这样,我会尝试在我的机器上使用它。我不确定你是如何得出英伟达的结论的,但是Debug GDIAG给出了NVD3DUM!查询资源泄漏的几率为97%,所以我认为你可能是对的。我手头没有ATI卡,但会看看我能找到什么。另外,我测试了512x512纹理,正如你所说,最后剩下的堆很少。非常感谢你的帮助,这很有教育意义@BenOwen这很有趣。尽管最终令人沮丧,但答案似乎仍然是“太糟糕了,它坏了。请尽量避免锋利的边缘。”:D发现一台装有旧ATI FireGL的机器,不幸的是,它仍然可以复制。我想可能是ATI驱动程序也坏了,但问题似乎出在其他地方。@BenOwen一个有趣的事情是,泄漏似乎不是确定性的-泄漏内存的数量似乎与纹理的数量(或其总大小)不是线性的。这可能意味着出现问题的原因是对共享内存的错误访问。这个问题似乎