为什么静态方法在创建 VBO 时会占用内存?



我有一个程序,它在屏幕上绘制六个字段,每个字段包含大约2000个顶点。为了创建这些VBO,我需要使用Buffer对象(Int/Foat)。我需要能够将顶点位置等保存到一个xml文件中,所以我想序列化模型对象,转换为B64并将其保存为字符串。问题是缓冲区对象不可序列化。

因此,为了解决这个问题,我从模型对象中删除了所有VBO代码(它最初是从一个单独的类扩展而来的),并创建了静态方法来创建我的VBO。因此,我调用静态方法为模型创建VBO,然后返回句柄,这样我就可以调用渲染、更新顶点等。然而,当创建模型时,这会严重增加内存。

为什么会这样?最初,内存使用情况甚至不明显。现在它使JVM崩溃。我没有更改任何代码逻辑,方法是相同的,只是现在它们是静态的,并传递回句柄。静态方法在创建VBO时会以某种方式使用更多内存吗?我以为会少一点?我确实会在使用后清除所有缓冲区。我确实处理掉了所有被淘汰的模型。

编辑:这是包含静态方法的Render类

package Drawing;
import static org.lwjgl.opengl.GL11.GL_FLOAT;
import static org.lwjgl.opengl.GL15.GL_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_DYNAMIC_DRAW;
import static org.lwjgl.opengl.GL15.GL_ELEMENT_ARRAY_BUFFER;
import static org.lwjgl.opengl.GL15.GL_STATIC_DRAW;
import static org.lwjgl.opengl.GL15.glBindBuffer;
import static org.lwjgl.opengl.GL15.glBufferData;
import static org.lwjgl.opengl.GL15.glBufferSubData;
import static org.lwjgl.opengl.GL15.glGenBuffers;
import static org.lwjgl.opengl.GL20.glEnableVertexAttribArray;
import static org.lwjgl.opengl.GL20.glVertexAttribPointer;
import static org.lwjgl.opengl.GL30.glBindVertexArray;
import static org.lwjgl.opengl.GL30.glGenVertexArrays;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import org.lwjgl.BufferUtils;
/**
* This class calls all vbo functions in a static way which allows me to 
 * separate the Int/FloatBuffers from the model classes like Cube and
 * Quad.  Int/FloatBuffers will not serialize so the Cube/Quad classes
 * cannot be saved to file.  Keeping them static and separated 
 * will overcome this problem.
 */
public class Render {
static int VERTEXCOUNT = 0;//((QUAD_SIZE * QUAD_SIZE) * 12);
static FloatBuffer fbData = null;//BufferUtils.createFloatBuffer(VERTEXCOUNT);
static FloatBuffer fbNorm = null;//BufferUtils.createFloatBuffer(VERTEXCOUNT);
static FloatBuffer fbtex = null;//BufferUtils.createFloatBuffer((VERTEXCOUNT / 12) * 8);
static IntBuffer Indices = null;
private static int _VAOHandle = 0;
private static IntBuffer vboHandles;
static final int POSITION_INDEX = 0; // index of vertex attribute "in_Position"
static final int NORMALS_IDX = 1;
static final int TEXTURE_IDX = 2;
static final int IBO_IDX = 3;
public static VBOIndexes createVBO(int QUAD_SIZE,
        float[] vertBuffer,
        float[] normals,
        float[] UVs,
        int[] idxBuffer)  throws Exception {
    VBOIndexes vboINDEXES = new VBOIndexes();
    try{
        VERTEXCOUNT = (int) ((QUAD_SIZE * QUAD_SIZE) * 12);
        fbData = BufferUtils.createFloatBuffer(VERTEXCOUNT);
        fbNorm = BufferUtils.createFloatBuffer(VERTEXCOUNT);
        fbtex = BufferUtils.createFloatBuffer((VERTEXCOUNT / 12) * 8);
        Indices = BufferUtils.createIntBuffer(VERTEXCOUNT / 2);

        _VAOHandle = glGenVertexArrays();
        vboINDEXES.VAOHandle = _VAOHandle;
        System.out.println("VAOHandle is : " + _VAOHandle);
        glBindVertexArray(_VAOHandle);
        vboHandles =  BufferUtils.createIntBuffer(4);
        glGenBuffers(vboHandles);
        vboINDEXES.idxPOS = vboHandles.get(POSITION_INDEX);
        vboINDEXES.idxNORM = vboHandles.get(NORMALS_IDX);
        vboINDEXES.idxTEX = vboHandles.get(TEXTURE_IDX);
        vboINDEXES.idxIBO = vboHandles.get(IBO_IDX);
        //FloatBuffer fbData = BufferUtils.createFloatBuffer(vertBuffer.length);
        fbData.put(vertBuffer);
        fbData.rewind(); // rewind, otherwise LWJGL thinks our buffer is empty
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX));
        glBufferData(GL_ARRAY_BUFFER, fbData, GL_DYNAMIC_DRAW);
        fbData.clear(); //don't need this anymore  

        //populate the normals buffer
        //FloatBuffer fbNorm = BufferUtils.createFloatBuffer(normalsBuffer.length );
        fbNorm.put(normals);
        fbNorm.rewind();
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(NORMALS_IDX)); //the vertex data
        glBufferData(GL_ARRAY_BUFFER, fbNorm, GL_STATIC_DRAW);
        fbNorm.clear(); //don't need this anymore 
        //populate the texture buffer
        fbtex.put(UVs);  
        fbtex.rewind();
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(TEXTURE_IDX)); 
        glBufferData(GL_ARRAY_BUFFER, fbtex, GL_DYNAMIC_DRAW);
        fbtex.clear(); //don't need this anymore  
        Indices.put(idxBuffer);
        Indices.rewind();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(POSITION_INDEX);
        glEnableVertexAttribArray(NORMALS_IDX);
        glEnableVertexAttribArray(TEXTURE_IDX);
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX)); 
        glVertexAttribPointer(0,3, GL_FLOAT, false,0,0);    
        //normals
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(NORMALS_IDX));
        glVertexAttribPointer(1, 3, GL_FLOAT, false, 0, 0);  
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(TEXTURE_IDX));
        glVertexAttribPointer(2, 2, GL_FLOAT, false, 0, 0); 
        //bind IBO
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));
        glBindVertexArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);

        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
        Indices.clear();
    }catch (Exception ex){
        System.out.println("createVBO: " + ex.getMessage());
        throw ex;
    }
    return vboINDEXES;
}
public static VBOIndexes createLineVBO( float[] vertBuffer,
                            int[] idxBuffer)  throws Exception {
    VBOIndexes vboINDEXES = new VBOIndexes();
    try{
        fbData = BufferUtils.createFloatBuffer(vertBuffer.length);
        Indices = BufferUtils.createIntBuffer(vertBuffer.length / 2);
        _VAOHandle = glGenVertexArrays();
        vboINDEXES.VAOHandle = _VAOHandle;
        glBindVertexArray(_VAOHandle);
        vboHandles =  BufferUtils.createIntBuffer(4);
        glGenBuffers(vboHandles);
        vboINDEXES.idxPOS = vboHandles.get(POSITION_INDEX);
        vboINDEXES.idxIBO = vboHandles.get(IBO_IDX);
        fbData.put(vertBuffer);
        fbData.rewind(); // rewind, otherwise LWJGL thinks our buffer is empty
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX));
        glBufferData(GL_ARRAY_BUFFER, fbData, GL_STATIC_DRAW);
        fbData.clear(); //don't need this anymore  
        //IntBuffer Indices = BufferUtils.createIntBuffer(idxBuffer.length);
        Indices.put(idxBuffer);
        Indices.rewind();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));
        //Util.checkGLError();
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, Indices, GL_STATIC_DRAW);
        glEnableVertexAttribArray(POSITION_INDEX);
        glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX)); 
        glVertexAttribPointer(0,3, GL_FLOAT, false,0,0);    
        //bind IBO
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vboHandles.get(IBO_IDX));
        Indices.clear();
        glBindVertexArray(0);
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        //Util.checkGLError();
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    }catch (Exception ex){
        System.out.println("createVBO: " + ex.getMessage());
        throw ex;
    }
    return vboINDEXES;
}
  public static void updateVertices(int offset,
                            float[] vertBuffer,
                            int idxPOS)
  {
      //populate the vertex buffer
      FloatBuffer fbData = BufferUtils.createFloatBuffer(vertBuffer.length);
      fbData.put(vertBuffer);   
      fbData.rewind();
      //glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(POSITION_INDEX)); //the vertex data
      glBindBuffer(GL_ARRAY_BUFFER, idxPOS);
      glBufferSubData(GL_ARRAY_BUFFER, offset, fbData);
      fbData.clear(); //don't need this anymore  
  }
  public static void updateNormals(int offset,
                              float[] normals,
                              int idxNORM)
  {
      //populate the vertex buffer
      FloatBuffer fbData = BufferUtils.createFloatBuffer(normals.length);
      fbData.put(normals);
      fbData.rewind();
      //glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get( NORMALS_IDX)); //the vertex data
      glBindBuffer(GL_ARRAY_BUFFER, idxNORM);
      glBufferSubData(GL_ARRAY_BUFFER, 0, fbData);
      fbData.clear(); //don't need this anymore  
  }
  public static void updateTexture(int offset,
          float[] UVs,
          int idxTEX)
  {
      //populate the texture buffer
      FloatBuffer fbtex = BufferUtils.createFloatBuffer(UVs.length);
      fbtex.put( UVs );
      fbtex.rewind();
      //glBindBuffer(GL_ARRAY_BUFFER, vboHandles.get(TEXTURE_IDX)); //the texture data
      glBindBuffer(GL_ARRAY_BUFFER, idxTEX);
      glBufferSubData(GL_ARRAY_BUFFER, offset, fbtex);
      fbtex.clear(); //don't need this anymore  
  }
  public Render(){
  }
}

静态调用在字段(瓦片对象数组)的构造函数中进行,如下所示:

public Quad(Map<Integer, Cube> c, int SIZE) throws Exception{
//public Quad(ArrayList<Cube> c, int SIZE) throws Exception{
    QUAD_SIZE = SIZE;
    initArrays();
    initVBOData(SIZE);
    createVBO();
    cubes = c;
}

我相信答案是静态类不提供GC。随着所有数据的传递,创建VBO,G真的开始堆积起来。。。

您的代码看起来非常混乱,您应该花一些时间来更好地了解OpenGL的工作原理,并使其更干净、更可读。我建议你从这个样品中汲取灵感。

很少考虑:

  • 你根本不需要静电
  • 我不知道lwjgl,但我想它需要直接缓冲区,而且你不能保证它们会被垃圾收集器删除,所以你应该自己分配它们,当你不再需要它们时释放它们。我创建了一个小类来释放直接缓冲区,取自这里的JM3
  • 通过在vboINDEXES中保存opengl资源名称来避免冗余。您已经在直接使用vboHandles
  • 如果缓冲区的维度没有改变,只分配一次并保留它们(fbDatafbNormfbTex),就不需要clear()
  • 因此,当updateNormals()没有实例化新的缓冲区时,请使用一开始已经实例化的缓冲区
  • 从逻辑的角度来看,IBO_INDEX不应该是vboINDEXES的一部分
  • 当调用glVertexAttribPointer时,将包含属性索引的变量作为第一个参数传递,例如POSITION_INDEX

ps:index的复数是indexes

最新更新