2012-01-30 4 views
3

LWJGL을 기반으로하는 Java 응용 프로그램이 있습니다. 3x3 격자로 배열 된 9 개의 꼭지점 버퍼를 통해 지형을 렌더링 중입니다. 카메라가 특정 경계를지나 움직이면 9 개의 버퍼가 업데이트되거나 새로운 지형 집합으로 바뀝니다. 이 모든 것은 잘 작동합니다. 새로운 요소 블록이 9 요소 배열에 추가되면 약 5MB의 메모리가 증가합니다. 이것만으로도 충분합니다. 예상하지 못한 것은 이전 지형 덩어리가 차지하고 있던 5MB의 메모리가 정리되지 않는다는 것입니다.Java 메모리 누수가 감지되지 않음

나는 누군가 내 도움을 줄 수 있기를 바랄 정도로 내 Google-FU를 소진했습니다. VisualVM이 설치되어 실행 중입니다. 내가 이해할 수없는 것은 지형로드 및 언로드가 많은데도 Windows에서 내 응용 프로그램이 200MB라고 말하면서 나타납니다. 그러나 VisualVM 힙 덤프는 12MB 만 보여줍니다.

지형을로드하기위한 게임 루프가 "main"의 세 번째 스레드에서 실행되고 있지 않습니다. 누구든지 올바른 방향으로 나를 가리킬 수 있습니까? 나는 약간의 코드를 붙이 겠지만, 너무 커서 어떤 비트를 붙일 지 모르겠습니다.

while(Game.running) { 

     time = Sys.getTime(); 
     dt = (double)((time - lastTime))/1000.0; 
     lastTime = time; 

     GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT); 

     input.pollInput(cam, dt); 
     cam.update(terrain.getTerrainHeight()); 
     sun.render(); 
     terrain.updateNew(cam.getPosition()); 
     terrain.render(); 
     frameRendering(); 
     //testTriangle(); 
     Display.update(); 
    } 

메인 루프가 있습니다. 문제가 terrain.updateNew() 함수에서 발생하는 것 같습니다. 여기

: 렌더링 기능 여기

private boolean createVertexBuffer() 
{ 
    _vboVertexAttribues = ARBVertexBufferObject.glGenBuffersARB(); 
    _vboVertexIndices = ARBVertexBufferObject.glGenBuffersARB(); 
    //_vboVertexTexture = ARBVertexBufferObject.glGenBuffersARB(); 

    ARBVertexBufferObject.glBindBufferARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      _vboVertexAttribues 
    ); 

    ARBVertexBufferObject.glBufferDataARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      (VERTEX_SIZE * VERTEX_COUNT), 
      ARBVertexBufferObject.GL_STATIC_DRAW_ARB 
    ); 

    ByteBuffer vertextPositionAttributes = ARBVertexBufferObject.glMapBufferARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      ARBVertexBufferObject.GL_WRITE_ONLY_ARB, 
      (VERTEX_SIZE * VERTEX_COUNT), 
      null 
    ); 

    for(int i = 0; i < VERTEX_COUNT; i++) 
    { 
     vertextPositionAttributes.putDouble(_vPos[i].x); 
     vertextPositionAttributes.putDouble(_vPos[i].y); 
     vertextPositionAttributes.putDouble(_vPos[i].z); 
     vertextPositionAttributes.putDouble(_vNorm[i].x); 
     vertextPositionAttributes.putDouble(_vNorm[i].y); 
     vertextPositionAttributes.putDouble(_vNorm[i].z); 
     vertextPositionAttributes.putFloat(_color.x); 
     vertextPositionAttributes.putFloat(_color.y); 
     vertextPositionAttributes.putFloat(_color.z); 
     vertextPositionAttributes.putFloat(1.0f); 
    } 


    vertextPositionAttributes.flip(); 

    ARBVertexBufferObject.glUnmapBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB); 
    ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0);  

    vertextPositionAttributes.clear(); 
    vertextPositionAttributes = null; 
    // TEXTURE COORDS 
    /*ARBVertexBufferObject.glBindBufferARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      _vboVertexTexture 
      ); 

    ARBVertexBufferObject.glBufferDataARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      (TEXTURE_SIZE * VERTEX_COUNT), 
      ARBVertexBufferObject.GL_STATIC_DRAW_ARB 
     ); 

    ByteBuffer vertexTextureCoords = ARBVertexBufferObject.glMapBufferARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      ARBVertexBufferObject.GL_WRITE_ONLY_ARB, 
      (TEXTURE_SIZE * VERTEX_COUNT), 
      null 
     ); 

    for(int i = 0; i < VERTEX_COUNT; i++) 
    { 
     vertexTextureCoords.putFloat(_vTex[i].x); 
     vertexTextureCoords.putFloat(_vTex[i].y); 
    } 
    vertexTextureCoords.flip(); 

    ARBVertexBufferObject.glUnmapBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB); 
    ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 0);*/ 


    ARBVertexBufferObject.glBindBufferARB(
      ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 
      _vboVertexIndices 
    ); 

    ARBVertexBufferObject.glBufferDataARB(
      ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 
      (INDEX_SIZE * INDEX_COUNT), 
      ARBVertexBufferObject.GL_STATIC_DRAW_ARB 
    ); 

    ByteBuffer vertexIndices = ARBVertexBufferObject.glMapBufferARB(
      ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 
      ARBVertexBufferObject.GL_WRITE_ONLY_ARB, 
      (INDEX_SIZE * INDEX_COUNT), 
      null 
    ); 

    for(int i = 0; i < _nIndices.length; i++) 
    { 
     vertexIndices.putInt(_nIndices[i]); 
    } 

    vertexIndices.flip(); 

    ARBVertexBufferObject.glUnmapBufferARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB); 
    ARBVertexBufferObject.glBindBufferARB(ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 

    // Cleanup our crap 
    _fXs = null; 
    _fYs = null; 
    _fZs = null; 
    _vPos = null; 
    _vNorm = null; 
    _color = null; 
    _nIndices = null; 
    _vTex = null; 
    vertexIndices.clear(); 
    vertexIndices = null; 
    return true; 
} 

된다 : 여기

public void updateNew(Vector3f playerPos) 
{ 
    _playerPos.x = playerPos.x; 
    _playerPos.y = playerPos.y; 
    _playerPos.z = playerPos.z; 
    int width = TerrainChunk.CHUNK_WIDTH; 
    _westernBounds = _chunks[4].getOrigin().x + 0; 
    _easternBounds = _chunks[4].getOrigin().x + width - 0; 
    _northernBounds = _chunks[4].getOrigin().z + 0; 
    _southernBounds = _chunks[4].getOrigin().z + width - 0; 

    if(_playerPos.x < _westernBounds && !_needUpdate) 
    { 
     _needUpdate = true; 
     _inWestBounds = true; 
    } 

    if(_playerPos.x > _easternBounds && !_needUpdate) 
    { 
     _needUpdate = true; 
     _inEastBounds = true; 
    } 

    if(_playerPos.z < _northernBounds && !_needUpdate) 
    { 
     _needUpdate = true; 
     _inNorthBounds = true; 
    } 

    if(_playerPos.z > _southernBounds && !_needUpdate) 
    { 
     _needUpdate = true; 
     _inSouthBounds = true; 
    } 

    if(_needUpdate) 
    { 
     long key = 0; 
     long key1 = 0; 
     long key2 = 0; 
     int[] coords = new int[2]; 
     HashMap<Integer, Long> needed = new HashMap<Integer, Long>(); 

     coords = calculateChunkCoords(0); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(0, key); 

     coords = calculateChunkCoords(1); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(1, key); 

     coords = calculateChunkCoords(2); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(2, key); 

     coords = calculateChunkCoords(3); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(3, key); 

     coords = calculateChunkCoords(4); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(4, key); 

     coords = calculateChunkCoords(5); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(5, key); 

     coords = calculateChunkCoords(6); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(6, key); 

     coords = calculateChunkCoords(7); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(7, key); 

     coords = calculateChunkCoords(8); 
     key1 = coords[0]; 
     key2 = coords[1]; 
     key = key1 << 32 | key2; 
     needed.put(8, key); 

     // copy the chunks we have into a searchable has map 
     HashMap<Long, TerrainChunk> have = new HashMap<Long, TerrainChunk>(); 
     key1 = _chunks[0]._origin[0]; 
     key2 = _chunks[0]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[0], _chunks[0]._color)); 
     key1 = _chunks[1]._origin[0]; 
     key2 = _chunks[1]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[1], _chunks[1]._color)); 
     key1 = _chunks[2]._origin[0]; 
     key2 = _chunks[2]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[2], _chunks[2]._color)); 
     key1 = _chunks[3]._origin[0]; 
     key2 = _chunks[3]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[3], _chunks[3]._color)); 
     key1 = _chunks[4]._origin[0]; 
     key2 = _chunks[4]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[4], _chunks[4]._color)); 
     key1 = _chunks[5]._origin[0]; 
     key2 = _chunks[5]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[5], _chunks[5]._color)); 
     key1 = _chunks[6]._origin[0]; 
     key2 = _chunks[6]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[6], _chunks[6]._color)); 
     key1 = _chunks[7]._origin[0]; 
     key2 = _chunks[7]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[7], _chunks[7]._color)); 
     key1 = _chunks[8]._origin[0]; 
     key2 = _chunks[8]._origin[1]; 
     key = key1 << 32 | key2; 
     have.put(key, new TerrainChunk(_chunks[8], _chunks[8]._color)); 


     Set<Entry<Integer, Long>> set = needed.entrySet(); 
     Iterator<Entry<Integer, Long>> i = set.iterator(); 
     // Garbage cleanup? 
     while(i.hasNext()) 
     { 
      Map.Entry<Integer, Long> me = i.next(); 
      if(have.containsKey(me.getValue())) 
      { 
       _chunks[me.getKey()] = null; 
       _chunks[me.getKey()] = new TerrainChunk(have.get(me.getValue()), getColor(me.getKey())); 
      } else { 
       _chunks[me.getKey()].destroy(); 
       _chunks[me.getKey()] = null; 
       _chunks[me.getKey()] = new TerrainChunk(calculateChunkCoords(me.getKey()), getColor(me.getKey()), this); 
      } 
     } 
     _needUpdate = false; 
     have.clear(); 
     needed.clear(); 
     have = null; 
     needed = null; 
    } 
} 

는 정점 버퍼를 생성하는 기능입니다 공공 무효)은 ( {

렌더링
GL11.glEnableClientState(GL11.GL_VERTEX_ARRAY); 
    GL11.glEnableClientState(GL11.GL_NORMAL_ARRAY); 
    GL11.glEnableClientState(GL11.GL_COLOR_ARRAY); 
    ARBVertexBufferObject.glBindBufferARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      _vboVertexAttribues 
    ); 

    ARBVertexBufferObject.glBindBufferARB(
      ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 
      _vboVertexIndices 
    ); 

    GL11.glVertexPointer(
      3, 
      GL11.GL_DOUBLE, 
      VERTEX_SIZE, 
      0 
    ); 

    GL11.glNormalPointer(
      GL11.GL_DOUBLE, 
      VERTEX_SIZE, 
      NORMAL_SIZE 
    ); 

    GL11.glColorPointer(
      4, 
      GL11.GL_FLOAT, 
      VERTEX_SIZE, 
      POSITION_SIZE + NORMAL_SIZE 
    ); 


    GL11.glDrawElements(
      GL11.GL_TRIANGLE_STRIP, 
      INDEX_COUNT, 
      GL11.GL_UNSIGNED_INT, 
      0 
    ); 

    ARBVertexBufferObject.glBindBufferARB(
      ARBVertexBufferObject.GL_ARRAY_BUFFER_ARB, 
      0 
    ); 

    ARBVertexBufferObject.glBindBufferARB(
      ARBVertexBufferObject.GL_ELEMENT_ARRAY_BUFFER_ARB, 
      0 
    ); 

    GL11.glDisableClientState(GL11.GL_VERTEX_ARRAY); 
    GL11.glDisableClientState(GL11.GL_NORMAL_ARRAY); 
    GL11.glDisableClientState(GL11.GL_COLOR_ARRAY); 
} 

도움이나 도움을 미리 감사드립니다. .

+1

응용 프로그램에 실제로 메모리가 부족합니까? JVM은 메모리를 자주 공개하지 않으며 GC는 실제로 필요할 때만 실행됩니다. JVM에 실제로 GC를 수행하여 어떤 일이 발생하는지 확인해 보았습니다. JVM이 실제로 메모리를 비울 수 없는지 확인하기 위해 더 낮은 -Xmx 값을 사용해 보셨습니까? – Rich

+0

왜 5MB가 증가 할 것으로 예상됩니까? 각 버퍼는 약 5MB/9 ?? – UmNyobe

+0

가비지 콜렉터를 수동으로 실행했는데, 이는 virtualVM에서 힙 크기를 변경하지만 OS 메모리 할당은 변경하지 않습니다. – jasonlg3d

답변

4

Java VM이 OS에서 메모리를 할당하는 방식, 특히 힙이 축소되는 경우에도 페이지를 해제하지 않는 경향이 있지만 힙이 다시 커지는 경우를 대비하여 유지하는 것이 좋지 않을까 생각합니다.

그러나 코드에서의 메모리 누출에 관한 한, 중요한 것은 VisualVM에서 힙 크기가 무엇인지 말하는 것입니다. 안정적이라면 거기에 누수가 없습니다.

또한 Java VM 자체가 실제 또는 가상 메모리를 사용하는 많은 원시 라이브러리 및 기타 요소를 사용하므로 각 Java 프로세스에 거의 일정한 오버 헤드가 있음을 고려해야합니다.

(This도 도움이 될 수 있습니다.)

+0

흥미로운 읽기 감사드립니다. – jasonlg3d

2

누수가 기본이되는 네이티브 라이브러리 내부에서 발생 될 수 있습니다. 그것은 LWJGL 네이티브 C 라이브러리 (OpenGL, OpenAL, 등 ..)에 바인딩 된 것, 그리고 거기에 임시 메모리 버퍼가 결코 공개되는 디스플레이에 사용되는 용의자. 이것은 VisualVM이 단지 12 MB (그가 처리하고있는 객체)를 보여주고 Windows는 200 MB (JVM과 GC 내부에서 생성 된 데이터와 C 라이브러리에서 사용되는 데이터)를 보여주는 이유를 설명합니다.

프레임 워크를 올바르게 사용하고 있습니까?

편집 :

나는이 특정 라이브러리에 익숙하지이기 때문에 내가 잘못 될 수 있지만 실제로 당신이 작업 \ 메모리 할당에 대한 기본 라이브러리를 사용하고 있습니다.

는 모든 벌금을하고있는 것 같다,하지만 난 당신의 버퍼를 할당

ARBBufferObject.glGenBuffersARB

나타났습니다. 당신이

ARBBufferObject.glDeleteBuffersARB

전화를 걸거나 메모리에 유지됩니다 버퍼를 종료 할 때까지, 그래서이 방법 은 C 기본 포장된다. createVertexBuffer()에 의해 생성 된 데이터의 수명주기, 호출 횟수, 그리고 사용자와 GPU 모두가이 작업을 완료하지 않은 경우 버퍼를 삭제해야합니다.

이번에도 OpenGl의이 측면을 알지 못해서 누군가 당신을 도울 가능성이 높습니다. 당신은 API of ARBBufferObjectC++ Wiki

+0

나는 생각한다. 그러나 LWJGL을 처음 접했을 때 나는 그렇지 않다는 가능성을 배제 할 수 없습니다. 나는 원래의 포스트에 버텍스 생성 함수를 붙여 넣었다. – jasonlg3d

1

에서 논의 된 하나의 대답은 간단과 동일 함을주의 사항 :이 제어 GC에서 존재하는 것을 의미한다 무엇을 당신이 "vertextPositionAttributes"의 정점을 넣어 버퍼 대부분의 아마 직접 버퍼입니다 heap이며 JVisualVM에는 보이지 않습니다.