2010-07-29 111 views
7

我有一个绘制和旋转立方体的类。每次我旋转立方体我重新加载与立方体的新值的缓冲区。OutOfMemory绘制立方体时出现异常

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); 
    } 

然后调用Cube.Draw方法Game.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); 
    } 

几分钟后,还是让我得到就行了内存溢出异常:

buffer.SetData<VertexPositionNormalTexture>(verts); 

有人能请解释为什么会发生这种情况,以及我能做些什么来解决这个问题。

+0

喜,@harryovers,你有没有找到解决办法,带着这种“BUG”,我觉得选择XNA太难过了。 – 2013-01-06 14:38:37

+0

@DuSijun我确实得到了这个工作,但它是2。5年前,所以我真的不记得很多关于它的细节抱歉。 – harryovers 2013-01-23 19:07:22

回答

8

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

我会讲更多关于XNA中的非托管资源my answer to this question

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

你真的应该做的是创建最小必要的顶点缓冲区只有一次。做这个的理想场所是在你的LoadContent功能(然后Dispose()他们在你的UnloadContent功能)。如果您有大量的多维数据集,您只需要一个描述多维数据集的顶点缓冲区,每次绘制多维数据集时都要重复使用。

很明显,你不想在同一个地方绘制所有的立方体。这是世界矩阵的用途。每次绘制立方体时,请将BasicEffect.World设置为该立方体的转换矩阵,并调用Apply()

(您直接设置WorldViewProj的方式是确定了。但是用漂亮的API,没错,是更好)。

如果旋转是你想要什么,用Matrix.CreateFromYawPitchRoll(yaw, pitch, roll)来创建变换矩阵。

有关这方面的更多详细信息,您的问题与another question I have answered类似。

(需要注意的是,如果顶点自己确实改变每一帧,你应该使用DrawUserPrimitives。但是请注意,这仍然是相当不是让顶点着色器在GPU上处理任何转换慢。)

0

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

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

+0

所有对每个缓冲区的引用都被删除了,所以我会争辩说,如果垃圾收集器是好的,它应该知道删除旧的不再使用的缓冲区。它不像旧的缓冲区被存储在列表或其他东西中。我错了吗?在任何情况下,它肯定不是要走的路,因为重复的分配和释放非常低效,因为每次调用LoadBuffer时都会使用“新VertexBuffer”进行操作。 – Ricket 2010-07-29 19:06:15

+0

@Ricket - 重复的分配是令我感到震惊的事情,没有任何相反的证据可以使它意识到旧缓冲区没有被释放。 – ChrisF 2010-07-29 19:40:20

+0

@Ricket GC不知道支持顶点缓冲区的非托管资源。这就是为什么它认为它有很多记忆,当它没有。 – 2010-07-30 07:31:56

相关问题