绘制多维数据集时出现OutOfMemory异常

时间:2010-07-29 15:56:52

标签: .net xna 3d out-of-memory

我有一个绘制和旋转立方体的类。每次我旋转立方体时,我都会使用新的立方体值重新加载缓冲区。

    public void LoadBuffer(GraphicsDevice graphicsDevice)
    {
        buffer = new VertexBuffer(graphicsDevice, VertexPositionNormalTexture.VertexDeclaration, triangles * 3, BufferUsage.None);
        buffer.SetData<VertexPositionNormalTexture>(verts);
        graphicsDevice.SetVertexBuffer(buffer);
    }

    public void Draw(GraphicsDevice graphicsDevice)
    {
        graphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, triangles);
    }

然后在Game.Draw中调用Cube.Draw方法

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(ClearOptions.DepthBuffer | ClearOptions.Target, Color.White, 1f, 0);

        basicEffect.Parameters["WorldViewProj"].SetValue(world * view * projection);

        EffectPass pass = basicEffect.CurrentTechnique.Passes[0];
        if (pass != null)
        {
            pass.Apply();
            cube1.LoadBuffer(GraphicsDevice);
            cube1.Draw(GraphicsDevice);
            cube2.LoadBuffer(GraphicsDevice);
            cube2.Draw(GraphicsDevice);
            cube3.LoadBuffer(GraphicsDevice);
            cube3.Draw(GraphicsDevice);
        }
        base.Draw(gameTime);
    }

几分钟左右后,我在行上得到OutOfMemory异常:

buffer.SetData<VertexPositionNormalTexture>(verts);

有人可以解释为什么会这样,以及我能做些什么来解决它。

2 个答案:

答案 0 :(得分:8)

顶点缓冲区是非托管资源。垃圾收集器不知道他们在幕后使用了一大堆非托管内存(和GPU资源)。它所知道的只是每个人使用的微小的托管内存。

我在my answer to this question中详细介绍了XNA中的非托管资源。

您可以在泄漏之前调用每个Dispose()上的VertexBuffer(但在绘制完成后,因为它仍然在使用!),以释放非托管资源。这样可以避免内存不足错误,但仍然会很慢!

你真正应该做的是只创建一次所需的最小顶点缓冲区。执行此操作的理想位置在LoadContent函数中(然后在Dispose()函数中UnloadContent)。如果你有一大堆立方体,你需要的只是一个描述立方体的顶点缓冲区,每次绘制立方体时都会重复使用。

显然,您不希望在同一个地方绘制所有立方体。这就是World矩阵的用途。每次绘制多维数据集时,请将BasicEffect.World设置为该多维数据集的转换矩阵,然后调用Apply()

(您直接设置WorldViewProj的方式也可以。但是,使用漂亮的API会更好。)

如果您想要轮换,请使用Matrix.CreateFromYawPitchRoll(yaw, pitch, roll)创建转换矩阵。

有关此问题的详细信息,您的问题与another question I have answered类似。

(注意,如果顶点本身确实改变了每一帧,你应该使用DrawUserPrimitives。但请注意,这仍然比让GPU上的顶点着色器处理要慢得多任何转变。)

答案 1 :(得分:0)

看起来你每帧都在创建一个新的顶点缓冲区,并且不允许旧的顶点缓冲区超出范围而被垃圾收集。事实上,你正在为每个立方体做这件事。

更好的方法是每帧更新顶点值,或者更好地更新每帧的立方体变换。