自发空指针触发事件时的异常

2022-09-03 02:56:25

我目前正在与LWJGL库结合使用JavaFX关卡编辑器,以实现OpenGL功能,从而使用多线程。

然而,我的问题是,有时当我触发JavaFX事件时(当我按下按钮/键等时)。我得到这个自发的.我似乎无法弄清楚错误何时发生的确切模式,并且由于某种奇怪的原因,堆栈跟踪不会为我提供异常发生的位置。我所知道的是,当我以某种方式与JavaFX应用程序线程交互时,它就会发生。java.lang.NullPointerException

但是,当它发生时,它不仅将其打印到控制台一次然后崩溃。发生的情况是,应用程序不断一遍又一遍地打印出错误消息,直到我强制关闭应用程序。当错误发生时,我似乎无法再触发某些特定事件。

这是我得到的自发重复错误消息:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Unknown Source)
at javafx.scene.Scene$ScenePulseListener.pulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Unknown Source)
at com.sun.javafx.tk.Toolkit$$Lambda$153/452428720.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Unknown Source)
at com.sun.javafx.tk.Toolkit.firePulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(Unknown Source)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$42/424424770.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(Unknown Source)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(Unknown Source)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/12064136.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

我猜它与“同步节点”有关。由于我正在使用多线程处理,以便使用OpenGL运行渲染循环,这可能与这种情况有关。我也使用Java8的Lambda表达式,显然正如它在错误日志中所说的那样,它也与它们有关。

我不指望有人能给我一个确切的答案,说明我的问题是什么,以及我做错了什么,因为我不提供任何代码(因为我的项目太大了,我不知道异常发生在哪里)。但是,我有几个一般性问题:

  1. 此错误日志是什么意思?

  2. 这是什么原因造成的?

  3. 为什么它没有向我提供有关异常发生地点的任何信息?

我设法从堆栈跟踪中获取行号,方法是将 Eclipse 中的 JRE 从 JRE 安装切换到 JDK 提供的 jar。这让我能够从编译的API中获取行号,例如JavaFX本身。

这是新的错误日志:

Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at javafx.scene.Scene$ScenePulseListener.synchronizeSceneNodes(Scene.java:2289)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2419)
at com.sun.javafx.tk.Toolkit.lambda$runPulse$30(Toolkit.java:314)
at com.sun.javafx.tk.Toolkit$$Lambda$153/478814140.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:313)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:340)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:525)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:505)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$400(QuantumToolkit.java:334)
at com.sun.javafx.tk.quantum.QuantumToolkit$$Lambda$42/1940618951.run(Unknown Source)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
at com.sun.glass.ui.win.WinApplication$$Lambda$38/640174177.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)

我的错误存在于JavaFX类中,可能在我的lambda表达式中的某个地方,因为它仍然显示(未知来源)的唯一位置是它也显示“lambda”的地方。也许堆栈跟踪无法在 lambda 中显示行号?

无论如何,这是返回 NullPointerException 的代码行:

if (node.getScene() == Scene.this)

这是在 JavaFX Scene 类中


答案 1

不是一个答案,只有来自解决一个非常相似的问题的建议 - 一个Swing问题。

为了避免任何猜测,我们应该查看源代码 - 解决“未知来源”部分。您提供的堆栈跟踪缺少行号。这是因为,标准 JRE 在编译时没有任何调试信息。有一次,我相信在Sun时代,人们可以下载一个单独的发行版,该发行版针对开发人员,其中包含所有调试符号。除了具有确切的行号之外,还允许在JDK的代码中设置断点。

我们可以从那里开始调查问题。

如果没有带有调试符号的 JRE,您可以随时尝试编译自己的符号!我曾经成功编译过JDK发行版附带的“src.zip”文件。虽然它不是自给自足的!有几个部分缺失,一些Linux特定的类等。来自JDK本身的javac在文件方面存在问题 - 它一直内存不足。幸运的是,Eclipse的javac编译器可以处理大型代码库并部分编译类。

然后,我在引导类路径上使用生成的 jar(src.zip使用调试符号编译)运行我的程序。通常,您不允许修改“java.”中的任何内容。“和”太阳”。包。使用引导类路径,您可以。

现在,回到你的特定问题:JavaFX和OpenGL都通过所谓的“线程限制”来解决多线程问题。这意味着,一切都是强制单线程的。也许,您的问题源于这样一个事实,即javaFx和OpenGL都有其单独的线程!我敢打赌,你在JavaFX的EDT之外做了一些互动。但是,这只是一个牵强附会的假设。尝试获取源代码行,我们可以从那里继续。

当我需要调试信息时,我正在遵循这里的答案:调试jdk源代码不能观察变量是什么

但是,可能不需要所有的工作!我刚刚了解到,您可以将源文件本身附加到引导类路径,如下所示:https://stackoverflow.com/a/10498425


更新

因此,似乎“节点”引用为空(我怀疑“this”是否为空)。下一步将标识空节点并找到添加它的确切时间。我可能会把一些断点(或打印输出语句)放在所有合理的“addNode”调用中 - 从你的程序。

从源代码(我快速浏览了 http://grepcode.com/file/repo1.maven.org/maven2/net.java.openjfx.backport/openjfx-78-backport/1.8.0-ea-b96.1/javafx/scene/Scene.java#2263)似乎,“null”引用来自“dirtyNodes”数组”。

我最好的选择通常是,你间接调用从正确的线程外部调用addToDirtyNodes(http://grepcode.com/file/repo1.maven.org/maven2/net.java.openjfx.backport/openjfx-78-backport/1.8.0-ea-b96.1/javafx/scene/Scene.java#503)。令我惊讶的是,有第一行检查它是否是从正确的行调用的:

Toolkit.getToolkit().checkFxUserThread();

您是否碰巧看到“不在FX应用程序线程上;currentThread = “ 在您的程序输出中?

让我们只希望,这不是JavaFX本身的错误。


答案 2

不要在非 GUI 线程上修改 GUI。

由于我没有看到你的代码,我不确定你到底在哪里做,但我遇到了同样的问题,事实证明我已经将一个GUI对象传递给了我的一类,该类在非GUI线程上运行了一个正在更新GUI对象的方法。所以不要那样做。


推荐