Java/LWJGL3优化渲染时glDrawElements触发EXCEPTION_ACCESS_VIOLATION错误
错误根因排查
1. Mesh资源提前释放问题
旧createModel方法渲染完成后会调用mesh.cleanUp()释放VAO、EBO等GPU资源,这个逻辑在单实体单次渲染时没问题,但批次渲染需要复用同一个Model的Mesh资源:
- 如果你没有修改
model.createModel()的实现,该方法大概率每次调用都会重新生成VAO/VBO/EBO,或者你在MeshLoader类中实现了finalize自动清理逻辑,当prepareModel中创建的MeshLoader局部变量被JVM GC回收时,会自动调用cleanUp释放你已经绑定的VAO/EBO资源,导致glDrawElements访问不存在的GPU缓冲区,触发空指针访问错误。
2. 重复调用createModel导致资源失效
你在prepareModel中调用了一次model.createModel()绑定VAO,又在glDrawElements参数中第二次调用model.createModel().getVertexCount():
- 如果
createModel方法每次调用都会销毁旧的Mesh资源、生成新的资源,那么第二次调用后你之前绑定的VAO已经被释放,OpenGL上下文找不到有效的索引缓冲区,就会报访问违例错误。
修复方案
- 首先修改
ModelLoader类,将createModel()加载得到的MeshLoader实例缓存为类成员变量,不要每次调用都重新生成Mesh资源,删除单次渲染后自动调用mesh.cleanUp()的逻辑,改为程序退出时统一清理所有Model的Mesh资源。 - 修改
Render类的批次渲染逻辑,复用同一个Mesh实例:
// 修改后的render方法 public void render(Map<ModelLoader, List<EntityLoader>> entities) { for(ModelLoader model:entities.keySet()) { MeshLoader mesh = model.getCachedMesh(); // 调用缓存的Mesh,不要每次重新生成 prepareModel(model, mesh); List<EntityLoader> batch = entities.get(model); for(EntityLoader entity : batch) { prepareEntity(entity); // 直接读取缓存Mesh的顶点数,不要重复调用createModel glDrawElements(GL_TRIANGLES, mesh.getVertexCount(), GL_UNSIGNED_INT, 0); } unbindModel(); } } // 修改prepareModel,传入缓存的Mesh实例 private void prepareModel(ModelLoader model, MeshLoader mesh) { glBindVertexArray(mesh.getVaoId()); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glEnableVertexAttribArray(2); shader.setUniformFloat("shineDamper", model.getShineDamper()); shader.setUniformFloat("reflectivity", model.getReflectivity()); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, model.getTexture()); glUniform1i(glGetUniformLocation(shader.getID(), "texture"), 0); }
- 新增程序退出前的统一资源清理逻辑,遍历所有
ModelLoader的缓存Mesh,调用cleanUp()释放GPU资源。
内容的提问来源于stack exchange,提问作者Renan Lima
相关产品推荐
相关产品推荐

