LWJGL / lwjgl3

LWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL, Vulkan, bgfx), audio (OpenAL, Opus), parallel computing (OpenCL, CUDA) and XR (OpenVR, LibOVR, OpenXR) applications.
https://www.lwjgl.org
BSD 3-Clause "New" or "Revised" License
4.82k stars 640 forks source link

Program with LWJGL crashes when I try to use VisualVM to profile it: "Cannot invoke "String.equals(Object)" because the return value of "java.lang.StackWalker$StackFrame.getFileName()" is null." #721

Closed Angular-Angel closed 2 years ago

Angular-Angel commented 2 years ago

Version

3.2.3

Platform

Linux x64

JDK

Graal CE 17

Module

LWJGL Core

Expected Behavior

The program should not crash and I should be able to profile it with VisualVM.

Current Behavior

When I run my application and start profiling it with Visualvm while it's on it's menu screen, it works okay, but I get a bunch of warnings in console:

OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended Profiler Agent: Waiting for connection on port 5140 (Protocol version: 20) Profiler Agent: Established connection with the tool *** Profiler engine warning: Cannot use ClassLoader.findLoadedClass() and/or ClassLoader.findBootstrapClass() in ClassLoaderManager

If I then try and launch the actual game, the game crashes. If I launch the game from menu and then start profiling, however, it does not crash - not sure why. It also lags extremely hard when profiling, but that may be normal and unavoidable.

VisualVM continues just fine. I was able to use VisualVM to profile the game before - but that was when I was building it with Maven. I recently switched to building it with Gradle.

Context

I am attempting to profile my game so I can increase it's performance.

Steps to Reproduce

I'm still trying to figure out how to reproduce this in a self contained example project. For the moment, you can reproduce it with my main project:

  1. Build the maven branch of: https://gitlab.com/AngularAngel/devilutil
  2. Build the gradle branch of: https://gitlab.com/AngularAngel/omnicraft,
  3. Run the game
  4. Run VisualVM and start profiling the game.
  5. Click 'Local Game' and then 'Play'

Your Environment

Build scan URL: https://scans.gradle.com/s/rb6e2lqivs2l4

Stacktrace or crash log output

Profiler Agent: Local accelerated session
*** Profiler engine warning: class jdk.internal.reflect.GeneratedMethodAccessor49 loaded by *** Profiler Agent Communication Thread
java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because the return value of "java.lang.StackWalker$StackFrame.getFileName()" is null
org.lwjgl.system.StackWalkUtil.isSameMethod(StackWalkUtil.java:44) at org.lwjgl.system.StackWalkUtil.isSameMethod(StackWalkUtil.java:38) at org.lwjgl.system.StackWalkUtil.lambda$stackWalkCheckPop$4(StackWalkUtil.java:72) at java.base/java.lang.StackStreamFactory$StackFrameTraverser.consumeFrames(StackStreamFactory.java:534) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.doStackWalk(StackStreamFactory.java:306) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.callStackWalk(Native Method) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.beginStackWalk(StackStreamFactory.java:370) at java.base/java.lang.StackStreamFactory$AbstractStackWalker.walk(StackStreamFactory.java:243) at java.base/java.lang.StackWalker.walk(StackWalker.java:498) at org.lwjgl.system.StackWalkUtil.stackWalkCheckPop(StackWalkUtil.java:62) at org.lwjgl.system.MemoryStack$DebugMemoryStack.pop(MemoryStack.java:200) at org.lwjgl.system.MemoryStack.close(MemoryStack.java:168) at com.samrj.devil.game.Mouse.getPos(Unknown Source) at net.angle.omnicraft.client.world.entities.ClientPlayer.<init>(ClientPlayer.java:54) at net.angle.omnicraft.client.world.entities.ClientPlayer.<init>(ClientPlayer.java:42) at net.angle.omnicraft.client.GameScreen.<init>(GameScreen.java:62) at net.angle.omnicraft.client.DebugClient.startSinglePlayerGame(DebugClient.java:157) at net.angle.omnicraft.client.WorldSelectScreen.lambda$createMenuWindow$0(WorldSelectScreen.java:45) at com.samrj.devil.gui.Button.activate(Button.java:87) at com.samrj.devil.gui.DUI.mouseButton(Unknown Source) at net.angle.omnicraft.client.MenuScreen.mouseButton(MenuScreen.java:65) at net.angle.omnicraft.client.DebugClient.mouseButton(DebugClient.java:89) at com.samrj.devil.game.Game.lambda$run$3(Unknown Source) at com.samrj.devil.game.Mouse.button(Unknown Source) at org.lwjgl.glfw.GLFWMouseButtonCallbackI.callback(GLFWMouseButtonCallbackI.java:36) at org.lwjgl.system.JNI.invokeV(Native Method) at org.lwjgl.glfw.GLFW.glfwPollEvents(Unknown Source) at com.samrj.devil.game.Game.run(Unknown Source) at net.angle.omnicraft.client.Client.run(Unknown Source) at net.angle.omnicraft.client.DebugClient.main(Unknown Source)
Spasi commented 2 years ago

Hey @Angular-Angel,

while it's on it's menu screen, it works okay, but I get a bunch of warnings in console

I have no idea what these warnings are, but probably unrelated to LWJGL.

If I then try and launch the actual game, the game crashes.

This is a bug in LWJGL, will be fixed in the next 3.3.1 snapshot (build 5).

If I launch the game from menu and then start profiling, however, it does not crash - not sure why.

I would be interested to learn why, but will need some help from you: Add a breakpoint at LWJGL's stackWalkCheckPop and print the stacktrace captured there. There should be a difference in the stacktrace between the two ways the game is launched.

It also lags extremely hard when profiling, but that may be normal and unavoidable.

It's because you're running with Configuration.DEBUG_STACK enabled. Both DEBUG_STACK and DEBUG_MEMORY_ALLOCATOR are expensive (read the javadoc for more info and a way to mitigate the impact). However, DEBUG_STACK is likely to be much more expensive than DEBUG_MEMORY_ALLOCATOR in most LWJGL applications, simply because stack allocations will be much more common than heap allocations.

On the other hand, stack allocation bugs are much more rare than heap allocation leaks and usually cause very quick application failures. For that reason, I would recommend against enabling DEBUG_STACK (even while developing your application), unless you have an actual problem related to stack allocation and cannot immediately find out why.

DEBUG_MEMORY_ALLOCATOR should also probably be disabled when profiling, it will very likely skew the performance hotspots and have a non-trivial impact on GC.

Angular-Angel commented 2 years ago

Okay, good to know! I will see if I can figure out that breakpoint, and disable DEBUG_STACK unless I need it for something, thank you!