Gluon+GraalVM编译的JavaFX程序在部分Linux系统显示空白窗口
JavaFX通过Gluon+GraalVM编译的二进制在部分Linux系统显示空白窗口问题
我开发了一款简单的JavaFX应用,通过Gluon Maven插件配合GraalVM编译为二进制文件,但该二进制文件在部分系统(例如全新安装的Linux桌面)上运行时仅显示空白窗口。本次编译通过Github Action执行,运行的命令为mvn -Pdesktop gluonfx:build gluonfx:package。
请问该二进制文件仅能在部分Linux系统正常运行的原因是什么,该如何解决?
pom.xml配置如下:
<plugin> <groupId>com.gluonhq</groupId> <artifactId>gluonfx-maven-plugin</artifactId> <version>1.0.4</version> <configuration> <mainClass>com.alinares.colorselectorfx.App</mainClass> <enableSWRendering>true</enableSWRendering> <nativeImageArgs> <arg>-Dprism.verbose=true</arg> </nativeImageArgs> </configuration> </plugin>

栈追踪信息如下:
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @1edfedf1' java.lang.UnsatisfiedLinkError: com.sun.pisces.JavaSurface.initialize(III)V [symbol: Java_com_sun_pisces_JavaSurface_initialize or Java_com_sun_pisces_JavaSurface_initialize__III] at com.oracle.svm.jni.access.JNINativeLinkage.getOrFindEntryPoint(JNINativeLinkage.java:153) at com.oracle.svm.jni.JNIGeneratedMethodSupport.nativeCallAddress(JNIGeneratedMethodSupport.java:57) at com.sun.pisces.JavaSurface.initialize(JavaSurface.java) at com.sun.pisces.JavaSurface.<init>(JavaSurface.java:45) at com.sun.prism.sw.SWRTTexture.<init>(SWRTTexture.java:51) at com.sun.prism.sw.SWResourceFactory.createRTTexture(SWResourceFactory.java:135) at com.sun.prism.sw.SWResourceFactory.createRTTexture(SWResourceFactory.java:124) at com.sun.javafx.tk.quantum.UploadingPainter.run(UploadingPainter.java:125) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:126) at java.lang.Thread.run(Thread.java:829) at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:552) at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)

更新信息
为二进制文件添加-Dprism.verbose=true参数后运行,日志如下:
Aug 19, 2021 10:58:33 PM com.sun.javafx.application.PlatformImpl startup WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @11bd803' Prism pipeline init order: es2 sw Using Double Precision Marlin Rasterizer Using dirty region optimizations Not using texture mask for primitives Not forcing power of 2 sizes for textures Using hardware CLAMP_TO_ZERO mode Opting in for HiDPI pixel scaling Prism pipeline name = com.sun.prism.es2.ES2Pipeline Loading ES2 native library ... prism_es2 succeeded. GLFactory using com.sun.prism.es2.X11GLFactory (X) Got class = class com.sun.prism.es2.ES2Pipeline Failed Graphics Hardware Qualifier check. System GPU doesn't meet the es2 pipe requirement GraphicsPipeline.createPipeline: error initializing pipeline com.sun.prism.es2.ES2Pipeline *** Fallback to Prism SW pipeline Prism pipeline name = com.sun.prism.sw.SWPipeline (X) Got class = class com.sun.prism.sw.SWPipeline Initialized prism pipeline: com.sun.prism.sw.SWPipeline vsync: true vpipe: false java.lang.UnsatisfiedLinkError: com.sun.pisces.JavaSurface.initialize(III)V [symbol: Java_com_sun_pisces_JavaSurface_initialize or Java_com_sun_pisces_JavaSurface_initialize__III] at com.oracle.svm.jni.access.JNINativeLinkage.getOrFindEntryPoint(JNINativeLinkage.java:153) at com.oracle.svm.jni.JNIGeneratedMethodSupport.nativeCallAddress(JNIGeneratedMethodSupport.java:57) at com.sun.pisces.JavaSurface.initialize(JavaSurface.java) at com.sun.pisces.JavaSurface.<init>(JavaSurface.java:45) at com.sun.prism.sw.SWRTTexture.<init>(SWRTTexture.java:51) at com.sun.prism.sw.SWResourceFactory.createRTTexture(SWResourceFactory.java:135) at com.sun.prism.sw.SWResourceFactory.createRTTexture(SWResourceFactory.java:124) at com.sun.javafx.tk.quantum.UploadingPainter.run(UploadingPainter.java:125) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) at com.sun.javafx.tk.RenderJob.run(RenderJob.java:58) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at com.sun.javafx.tk.quantum.QuantumRenderer$PipelineRunnable.run(QuantumRenderer.java:126) at java.lang.Thread.run(Thread.java:829) at com.oracle.svm.core.thread.JavaThreads.threadStartRoutine(JavaThreads.java:567) at com.oracle.svm.core.posix.thread.PosixJavaThreads.pthreadStartRoutine(PosixJavaThreads.java:192)
目前我已经在pom.xml中添加了<enableSWRendering>true</enableSWRendering>配置,且在执行gluonfx:runagent后,将com.sun.pisces.JavaSurface.initialize分别添加到了reflect-config.json和jni-config.json文件中,但问题仍未解决。
问题原因
- 触发条件差异:在显卡驱动正常、支持OpenGL 2.0+的系统上,JavaFX默认使用ES2硬件渲染管线,不会触发软件渲染逻辑,因此不会调用
com.sun.pisces.JavaSurface的native方法,运行正常;而在无GPU、驱动缺失或老旧的系统上,ES2管线初始化失败,回退到SW软件渲染管线,此时就会调用pisces库的native方法。 - 根本原因:你使用的
gluonfx-maven-plugin 1.0.4版本存在已知bug,手动添加的JNI配置无法正确将pisces库的native符号打包进最终二进制文件,静态编译时遗漏了该方法的符号链接,回退到软件渲染时就会抛出UnsatisfiedLinkError,导致界面绘制失败显示空白窗口。
解决方案
- 方案1:优先升级
gluonfx-maven-plugin到1.0.8及以上版本,该版本已经修复了软件渲染相关的native符号打包问题,不需要额外手动添加JNI/反射配置,重新编译即可解决问题。 - 方案2:如果无法升级插件,在pom的
nativeImageArgs中添加参数-H:JNIConfigurationResources=META-INF/native-image/jni-config.json,确认你的jni-config.json中完整配置了com.sun.pisces.*包下所有native方法的入口;同时在<runtimeArgs>中添加-Dprism.forceGPU=true参数,优先强制使用硬件渲染,降低软件渲染触发概率。 - 方案3:编译时选用兼容性更好的系统环境,Github Action的编译镜像选用Ubuntu 20.04版本,避免高版本glibc编译出的二进制在低版本系统上出现符号不兼容问题,提升二进制文件的跨系统兼容性。
内容的提问来源于stack exchange,提问作者user547972
相关产品推荐
相关产品推荐

