2010-07-29 4 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); 
    } 

는 몇 분 후 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); 
    } 

에 Cube.Draw 메소드를 호출하거나 그래서 난 라인 상에 OutOfMemory 예외를 얻을 :

buffer.SetData<VertexPositionNormalTexture>(verts); 

수 누군가 이것이 왜 일어나고 있는지 그리고 내가 그것을 해결하기 위해 무엇을 할 수 있는지 설명해주십시오.

+0

안녕 , @ 해리 오버, "BUG"같은 이런 종류의 일을 발견 했습니까? XNA를 선택하기가 너무 슬프다. –

+0

@DuSijun 나는 이것이 작동하도록 만들었지 만 2였다.5 년 전 미안하지만 그것에 대한 자세한 내용을 많이 기억하지 못했습니다. – harryovers

답변

8

정점 버퍼는 관리되지 않는 리소스입니다. 가비지 컬렉터 을 사용하여 무대 뒤에서 전체 관리되지 않는 메모리 (및 GPU 리소스)를 사용하고 있음을 알 수 없습니다. 모든 것이 알고있는 것은 각자 사용하는 작은 관리 메모리입니다.

XNA의 관리되지 않는 리소스에 대해 my answer to this question에 대해 자세히 설명합니다.

누출되기 전에 각 VertexBufferDispose()을 호출 할 수 있습니다 (그리기가 끝난 후에도 여전히 사용 중이므로!). 관리되지 않는 리소스를 해제 할 수 있습니다. 이것은 메모리 부족 오류를 피할 수 있지만 여전히 매우 느릴 것입니다!

정말 필요한 것은 최소 필요한 버텍스 버퍼 을 한번만 생성하는 것입니다.. 이 작업을 수행 할 수있는 이상적인 장소는 LoadContent 함수입니다 (UnloadContent 함수에서 Dispose()). 전체 큐브를 가지고 있다면 큐브를 그릴 때마다 다시 사용하는 큐브를 설명하는 단일 정점 버퍼 만 있으면됩니다.

분명히 같은 장소에 모든 큐브를 그리지 않을 것입니다. 이것은 월드 매트릭스가있는 것입니다. 큐브를 그릴 때마다 해당 큐브의 변형 행렬에 BasicEffect.World을 설정하고 Apply()을 호출하십시오.

(직접 WorldViewProj을 설정하는 방법도 괜찮습니다.하지만 좋은 API를 사용하는 것이 아니라,이다 좋네요.) 회전이 당신이 원하는 경우

,

당신의 변환 행렬을 만들 Matrix.CreateFromYawPitchRoll(yaw, pitch, roll)를 사용합니다.

이 문제에 대한 자세한 내용은 another question I have answered과 유사합니다.

이 (정점 자신 정말 각 프레임을 변경을 할 경우, 당신은 DrawUserPrimitives를 사용한다, 그 참고. 그러나 여전히 모든 변환을 처리하는 GPU에 정점 셰이더를시키는보다 느린 상당히 떨어져 있음을 알아.)

0

프레임마다 새 버텍스 버퍼를 만들고 쓰레기 수집을 위해 이전 버텍스 버퍼 범위를 벗어나는 것처럼 보이지 않습니다. 실제로 각 큐브에 대해이 작업을 수행하고 있습니다.

더 나은 방법은 각 프레임의 정점 값을 업데이트하거나 각 프레임에서 큐브의 변형을 더 잘 업데이트하는 것입니다.

+0

각 버퍼에 대한 모든 참조가 제거되었으므로 가비지 수집기가 좋았다면 오래된 더 이상 사용되지 않는 버퍼를 삭제해야한다는 것을 알고 있어야한다고 주장합니다. 이전 버퍼가 목록이나 다른 것에 저장되는 것과는 다릅니다. 내가 잘못? LoadBuffer를 호출 할 때마다 "새로운 VertexBuffer"가 반복적으로 할당 및 할당 해제를하는 것이 매우 비효율적이기 때문에 어떤 경우 든 확실히 갈 길이 아닙니다. – Ricket

+0

@Ricket - 반복 된 할당은 나에게 타격을주었습니다. 반대의 증거가 없으면 이전 버퍼가 해제되지 않는다는 아이디어에 도움이됩니다. – ChrisF

+0

@Ricket GC가 버텍스 버퍼를 관리하는 관리되지 않는 리소스에 대해 알지 못합니다. 그것이 기억의 과장을 가지고 있다고 생각하는 이유입니다. –

관련 문제