You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LWJGL调用glDrawArrays时JVM触发EXCEPTION_ACCESS_VIOLATION崩溃

调用glDrawArrays()时JVM触发EXCEPTION_ACCESS_VIOLATION崩溃问题排查与修复

问题背景

原问题为LWJGL渲染画面不显示,搭建最小复现示例后出现JVM崩溃,触发EXCEPTION_ACCESS_VIOLATION错误。已尝试每帧初始化顶点属性指针、设置GLFW错误回调与OpenGL调试消息回调,但未生成任何调试信息或错误日志。

环境信息

  • 运行环境:IntelliJ直接运行JDK17
  • LWJGL依赖:标准LWJGL3配置

复现代码

import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLUtil;

import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

public class MinimalExample {

    private static String readResource(String res) {
        try {
            InputStream is = MinimalExample.class.getResourceAsStream(res);
            String s = new String(is.readAllBytes(), StandardCharsets.UTF_8);
            is.close();
            return s;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    // vertex data buffer
    private static final ByteBuffer buf = ByteBuffer.allocateDirect(4096);

    // shader program
    static int program;

    // render objects
    static int vao;
    static int vbo;

    public static void main(String[] args) {
        // set buffer limit
        buf.limit(4096);

        // init glfw and create window
        GLFW.glfwInit();
        long window = GLFW.glfwCreateWindow(500, 500, "Hello", 0, 0);

        // create GL
        GLFW.glfwMakeContextCurrent(window);
        GL.createCapabilities();
        GLUtil.setupDebugMessageCallback(System.out);
        GLFW.glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.out));

        // create vertex objects
        vao = GL30.glGenVertexArrays();
        vbo = GL30.glGenBuffers();
        GL30.glBindVertexArray(vao);
        GL30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 7 * 4, 0);
        GL30.glVertexAttribPointer(1, 4, GL30.GL_FLOAT, false, 7 * 4, 0);
        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);
        GL30.glBindVertexArray(0);

        // compile and link shaders
        int vertexShader   = GL30.glCreateShader(GL30.GL_VERTEX_SHADER);
        int fragmentShader = GL30.glCreateShader(GL30.GL_FRAGMENT_SHADER);
        GL30.glShaderSource(vertexShader,   readResource("/test.vsh"));
        GL30.glShaderSource(fragmentShader, readResource("/test.fsh"));
        GL30.glCompileShader(vertexShader);
        GL30.glCompileShader(fragmentShader);
        program = GL30.glCreateProgram();
        GL30.glAttachShader(program, vertexShader);
        GL30.glAttachShader(program, fragmentShader);
        GL30.glLinkProgram(program);

        // render loop
        while (!GLFW.glfwWindowShouldClose(window)) {
            // poll events
            GLFW.glfwPollEvents();

            // clear screen
            GL30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
            GL30.glClear(GL30.GL_COLOR_BUFFER_BIT);

            // render
            render();

            // swap buffers
            GLFW.glfwSwapBuffers(window);
        }
    }

    static void render() {
        // put vertex data
        // manual to simulate graphics library
        putVec3(0.25f, 0.25f, 1f); putVec4(1.0f, 0.0f, 0.0f, 1.0f);
        putVec3(0.75f, 0.25f, 1f); putVec4(0.0f, 1.0f, 0.0f, 1.0f);
        putVec3(0.50f, 0.75f, 1f); putVec4(0.0f, 0.0f, 1.0f, 1.0f);

        // bind program
        GL30.glUseProgram(program);

        // bind vertex array
        GL30.glBindVertexArray(vao);
        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);

        // upload graphics data and draw
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo);
        GL30.glBufferData(GL30.GL_ARRAY_BUFFER, buf, GL30.GL_STATIC_DRAW);
        GL30.glDrawArrays(GL30.GL_TRIANGLES, 0, 3);
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, 0);
        GL30.glBindVertexArray(0);

        // reset vertex data buffer
        buf.position(0);
    }

    //////////////////////////////////////////

    static void putVec3(float x, float y, float z) {
        buf.putFloat(x).putFloat(y).putFloat(z);
    }

    static void putVec4(float x, float y, float z, float w) {
        buf.putFloat(x).putFloat(y).putFloat(z).putFloat(z);
    }

}

问题根源

  1. 顶点属性指针偏移错误:初始化VAO时,颜色属性的偏移量设为0,而颜色数据实际紧跟在3个float的位置数据之后,正确偏移量应为3 * 4(12字节),GPU读取越界内存直接触发访问违规。
  2. ByteBuffer位置未提前重置:render()方法中写入顶点数据前未重置ByteBuffer的position,第一次写入后position停在有效数据末尾,后续循环会继续往buffer后方写入非法数据,导致glBufferData读取超出有效范围的内存。
  3. putVec4方法笔误:最后一个参数错误使用z而非w,虽不直接导致崩溃,但会造成颜色数据异常。
  4. 缺少Shader编译/链接检查:代码未验证Shader编译和Program链接是否成功,若Shader存在语法错误,无效的Program会引发未知行为。

修复方案

1. 修正顶点属性偏移量

修改VAO初始化代码:

GL30.glVertexAttribPointer(1, 4, GL30.GL_FLOAT, false, 7 * 4, 3 * 4);

2. 写入顶点数据前重置ByteBuffer位置

在render()方法开头添加:

buf.position(0);

3. 修复putVec4方法笔误

static void putVec4(float x, float y, float z, float w) {
    buf.putFloat(x).putFloat(y).putFloat(z).putFloat(w);
}

4. 添加Shader编译/链接错误检查

在编译Shader和链接Program后添加检查逻辑:

// 检查顶点Shader编译
if (GL30.glGetShaderi(vertexShader, GL30.GL_COMPILE_STATUS) == GL30.GL_FALSE) {
    throw new RuntimeException("Vertex shader compile failed: " + GL30.glGetShaderInfoLog(vertexShader));
}
// 检查片段Shader编译
if (GL30.glGetShaderi(fragmentShader, GL30.GL_COMPILE_STATUS) == GL30.GL_FALSE) {
    throw new RuntimeException("Fragment shader compile failed: " + GL30.glGetShaderInfoLog(fragmentShader));
}
// 检查Program链接
if (GL30.glGetProgrami(program, GL30.GL_LINK_STATUS) == GL30.GL_FALSE) {
    throw new RuntimeException("Program link failed: " + GL30.glGetProgramInfoLog(program));
}

修复后的完整代码

import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWErrorCallback;
import org.lwjgl.opengl.GL;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLUtil;

import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

public class MinimalExample {

    private static String readResource(String res) {
        try {
            InputStream is = MinimalExample.class.getResourceAsStream(res);
            String s = new String(is.readAllBytes(), StandardCharsets.UTF_8);
            is.close();
            return s;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    // vertex data buffer
    private static final ByteBuffer buf = ByteBuffer.allocateDirect(4096);

    // shader program
    static int program;

    // render objects
    static int vao;
    static int vbo;

    public static void main(String[] args) {
        // set buffer limit
        buf.limit(4096);

        // init glfw and create window
        GLFW.glfwInit();
        long window = GLFW.glfwCreateWindow(500, 500, "Hello", 0, 0);

        // create GL
        GLFW.glfwMakeContextCurrent(window);
        GL.createCapabilities();
        GLUtil.setupDebugMessageCallback(System.out);
        GLFW.glfwSetErrorCallback(GLFWErrorCallback.createPrint(System.out));

        // create vertex objects
        vao = GL30.glGenVertexArrays();
        vbo = GL30.glGenBuffers();
        GL30.glBindVertexArray(vao);
        GL30.glVertexAttribPointer(0, 3, GL30.GL_FLOAT, false, 7 * 4, 0);
        // 修正颜色属性偏移量
        GL30.glVertexAttribPointer(1, 4, GL30.GL_FLOAT, false, 7 * 4, 3 * 4);
        GL30.glEnableVertexAttribArray(0);
        GL30.glEnableVertexAttribArray(1);
        GL30.glBindVertexArray(0);

        // compile and link shaders
        int vertexShader   = GL30.glCreateShader(GL30.GL_VERTEX_SHADER);
        int fragmentShader = GL30.glCreateShader(GL30.GL_FRAGMENT_SHADER);
        GL30.glShaderSource(vertexShader,   readResource("/test.vsh"));
        GL30.glShaderSource(fragmentShader, readResource("/test.fsh"));
        GL30.glCompileShader(vertexShader);
        GL30.glCompileShader(fragmentShader);

        // 检查Shader编译错误
        if (GL30.glGetShaderi(vertexShader, GL30.GL_COMPILE_STATUS) == GL30.GL_FALSE) {
            throw new RuntimeException("Vertex shader compile failed: " + GL30.glGetShaderInfoLog(vertexShader));
        }
        if (GL30.glGetShaderi(fragmentShader, GL30.GL_COMPILE_STATUS) == GL30.GL_FALSE) {
            throw new RuntimeException("Fragment shader compile failed: " + GL30.glGetShaderInfoLog(fragmentShader));
        }

        program = GL30.glCreateProgram();
        GL30.glAttachShader(program, vertexShader);
        GL30.glAttachShader(program, fragmentShader);
        GL30.glLinkProgram(program);

        // 检查Program链接错误
        if (GL30.glGetProgrami(program, GL30.GL_LINK_STATUS) == GL30.GL_FALSE) {
            throw new RuntimeException("Program link failed: " + GL30.glGetProgramInfoLog(program));
        }

        // 删除Shader,链接后不再需要
        GL30.glDeleteShader(vertexShader);
        GL30.glDeleteShader(fragmentShader);

        // render loop
        while (!GLFW.glfwWindowShouldClose(window)) {
            // poll events
            GLFW.glfwPollEvents();

            // clear screen
            GL30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
            GL30.glClear(GL30.GL_COLOR_BUFFER_BIT);

            // render
            render();

            // swap buffers
            GLFW.glfwSwapBuffers(window);
        }

        // 清理资源
        GL30.glDeleteVertexArrays(vao);
        GL30.glDeleteBuffers(vbo);
        GL30.glDeleteProgram(program);
        GLFW.glfwDestroyWindow(window);
        GLFW.glfwTerminate();
    }

    static void render() {
        // 重置buffer位置,准备写入新数据
        buf.position(0);

        // put vertex data
        // manual to simulate graphics library
        putVec3(0.25f, 0.25f, 1f); putVec4(1.0f, 0.0f, 0.0f, 1.0f);
        putVec3(0.75f, 0.25f, 1f); putVec4(0.0f, 1.0f, 0.0f, 1.0f);
        putVec3(0.50f, 0.75f, 1f); putVec4(0.0f, 0.0f, 1.0f, 1.0f);

        // 刷新buffer,确保数据写入完成
        buf.flip();

        // bind program
        GL30.glUseProgram(program);

        // bind vertex array
        GL30.glBindVertexArray(vao);

        // upload graphics data and draw
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, vbo);
        GL30.glBufferData(GL30.GL_ARRAY_BUFFER, buf, GL30.GL_STATIC_DRAW);
        GL30.glDrawArrays(GL30.GL_TRIANGLES, 0, 3);

        // 解绑资源
        GL30.glBindBuffer(GL30.GL_ARRAY_BUFFER, 0);
        GL30.glBindVertexArray(0);
        GL30.glUseProgram(0);
    }

    //////////////////////////////////////////

    static void putVec3(float x, float y, float z) {
        buf.putFloat(x).putFloat(y).putFloat(z);
    }

    static void putVec4(float x, float y, float z, float w) {
        buf.putFloat(x).putFloat(y).putFloat(z).putFloat(w);
    }

}

内容的提问来源于stack exchange,提问作者Orbyfied

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 05:05:14