游戏因回调失败而崩溃,因为闭包实例已被垃圾回收
Game crash with Callback failed because the closure instance has been garbage collected
我的小游戏有问题。我是 LJWGL3 的新手(使用了很长时间的 2),想实现一个在 window 和全屏模式之间切换的键。我已经可以毫无问题地做到这一点。但是现在如果我经常按这个键,我的游戏就会崩溃。有时更晚或更早。没有定时崩溃。我尝试了很多(3 小时),现在 运行 没有想法。有人知道我做错了什么吗?我无法 post 完整的源代码,因为它太多了。
我 post 把代码的一些重要部分放在这里。
首先是错误:
Exception in thread "main" org.lwjgl.system.libffi.ClosureError: Callback failed because the closure instance has been garbage collected.
at org.lwjgl.system.JNI.invokeIIPPPP(Native Method)
at org.lwjgl.glfw.GLFW.nglfwCreateWindow(GLFW.java:1146)
at org.lwjgl.glfw.GLFW.glfwCreateWindow(GLFW.java:1227)
at com.dungeon.gl.FullscreenCreation.setFullScreen(FullscreenCreation.java:63)
at com.dungeon.gl.GLAction.updateGL(GLAction.java:78)
at com.dungeon.MainAction.start(MainAction.java:69)
at com.dungeon.MainAction.main(MainAction.java:21)
这是我用来检查 KEY 是否按下的代码:
if(glfwGetKey(appID, GLFW_KEY_F) == GLFW_PRESS) {
FullscreenCreation.setFullScreen(!fullscreen);
}
这是我的 FullscreenCreation.java
public static void setFullScreen(boolean fullScreen) {
//i don't have copy the variables like fullscreen to here
if (fullscreen == fullScreen)
return;
fullscreen = fullScreen;
if (fullScreen) {
windowWIDTH = WIDTH;
windowHEIGHT = HEIGHT;
//get monitor resolution
ByteBuffer vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
WIDTH = GLFWvidmode.width(vidMode);
HEIGHT = GLFWvidmode.height(vidMode);
} else {
WIDTH = windowWIDTH;
HEIGHT = windowHEIGHT;
}
//create new window THIS IS THE POINT WHERE ITS CRASH AFTER A WHILE
long display = glfwCreateWindow(WIDTH, HEIGHT, MainAction.BASIC_WINDOW_TITLE, fullScreen ? glfwGetPrimaryMonitor() : 0, appID);
glfwDestroyWindow(appID); //kill the window (for now)
//add new callback for resizing the window
glfwSetCallback(display, GLFWWindowSizeCallback(new SAM() {
@Override
public void invoke(long window, int width, int height) {
if(width!=0 && height!=0) {
WIDTH=width;
HEIGHT=height;
isResize=true;
}
}
}));
//now apply the new fullscreen window
appID = display;
//some GL stuff for the new window
glfwMakeContextCurrent(appID);
GL.createCapabilities();
glfwSwapInterval(0); //disable vsync
//only call glEnable(GL_TEXTURE_2D), GL_BLEND ...
DisplayCreation.enableGLStuff();
isResize = true;
}
如果您需要更多代码,我会 post 更多。
您需要对您创建的每个回调保持强引用,因为垃圾收集器不知道它在本机代码中使用,因此会以其他方式收集它。
所以这意味着您必须将回调对象存储在一个字段中。
private static GLFWWindowSizeCallback sizeCallback;
//...
public static void setFullScreen(boolean fullScreen) {
//...
sizeCallback = GLFWWindowSizeCallback(new SAM() {
//...
};
glfwSetCallback(display, sizeCallback);
//...
}
然后,当您使用完回调后(即当您销毁 window 时),您只需释放它即可。
sizeCallback.release();
注意:要释放给定window的所有回调,也可以使用Callbacks.glfwReleaseCallbacks.
关于 LWJGL 2 和 3 之间的差异,您可以查看 migration guide,其中也包含对此问题的简要说明。
我的小游戏有问题。我是 LJWGL3 的新手(使用了很长时间的 2),想实现一个在 window 和全屏模式之间切换的键。我已经可以毫无问题地做到这一点。但是现在如果我经常按这个键,我的游戏就会崩溃。有时更晚或更早。没有定时崩溃。我尝试了很多(3 小时),现在 运行 没有想法。有人知道我做错了什么吗?我无法 post 完整的源代码,因为它太多了。 我 post 把代码的一些重要部分放在这里。 首先是错误:
Exception in thread "main" org.lwjgl.system.libffi.ClosureError: Callback failed because the closure instance has been garbage collected.
at org.lwjgl.system.JNI.invokeIIPPPP(Native Method)
at org.lwjgl.glfw.GLFW.nglfwCreateWindow(GLFW.java:1146)
at org.lwjgl.glfw.GLFW.glfwCreateWindow(GLFW.java:1227)
at com.dungeon.gl.FullscreenCreation.setFullScreen(FullscreenCreation.java:63)
at com.dungeon.gl.GLAction.updateGL(GLAction.java:78)
at com.dungeon.MainAction.start(MainAction.java:69)
at com.dungeon.MainAction.main(MainAction.java:21)
这是我用来检查 KEY 是否按下的代码:
if(glfwGetKey(appID, GLFW_KEY_F) == GLFW_PRESS) {
FullscreenCreation.setFullScreen(!fullscreen);
}
这是我的 FullscreenCreation.java
public static void setFullScreen(boolean fullScreen) {
//i don't have copy the variables like fullscreen to here
if (fullscreen == fullScreen)
return;
fullscreen = fullScreen;
if (fullScreen) {
windowWIDTH = WIDTH;
windowHEIGHT = HEIGHT;
//get monitor resolution
ByteBuffer vidMode = glfwGetVideoMode(glfwGetPrimaryMonitor());
WIDTH = GLFWvidmode.width(vidMode);
HEIGHT = GLFWvidmode.height(vidMode);
} else {
WIDTH = windowWIDTH;
HEIGHT = windowHEIGHT;
}
//create new window THIS IS THE POINT WHERE ITS CRASH AFTER A WHILE
long display = glfwCreateWindow(WIDTH, HEIGHT, MainAction.BASIC_WINDOW_TITLE, fullScreen ? glfwGetPrimaryMonitor() : 0, appID);
glfwDestroyWindow(appID); //kill the window (for now)
//add new callback for resizing the window
glfwSetCallback(display, GLFWWindowSizeCallback(new SAM() {
@Override
public void invoke(long window, int width, int height) {
if(width!=0 && height!=0) {
WIDTH=width;
HEIGHT=height;
isResize=true;
}
}
}));
//now apply the new fullscreen window
appID = display;
//some GL stuff for the new window
glfwMakeContextCurrent(appID);
GL.createCapabilities();
glfwSwapInterval(0); //disable vsync
//only call glEnable(GL_TEXTURE_2D), GL_BLEND ...
DisplayCreation.enableGLStuff();
isResize = true;
}
如果您需要更多代码,我会 post 更多。
您需要对您创建的每个回调保持强引用,因为垃圾收集器不知道它在本机代码中使用,因此会以其他方式收集它。
所以这意味着您必须将回调对象存储在一个字段中。
private static GLFWWindowSizeCallback sizeCallback;
//...
public static void setFullScreen(boolean fullScreen) {
//...
sizeCallback = GLFWWindowSizeCallback(new SAM() {
//...
};
glfwSetCallback(display, sizeCallback);
//...
}
然后,当您使用完回调后(即当您销毁 window 时),您只需释放它即可。
sizeCallback.release();
注意:要释放给定window的所有回调,也可以使用Callbacks.glfwReleaseCallbacks.
关于 LWJGL 2 和 3 之间的差异,您可以查看 migration guide,其中也包含对此问题的简要说明。