Java C++ 中的 JNI 启动器:在没有 JavaFX 的情况下工作,使用 JavaFX 的核心转储
Java JNI Launcher in C++: Works without JavaFX, Core Dump with JavaFX
我写了一个 C++ JNI Java 启动器。如果我启动一个不使用 JavaFX 的 java 程序,它会工作,但如果我尝试用它启动一个 JavaFX 程序,它会创建一个核心转储。这是代码:
仅当我使用本机启动器时才会发生核心转储。如果我 运行 具有相同参数的 JavaFX 程序在命令行中使用 java
,则没有问题。它 运行 符合预期。
Here's the content of the hs_err file, in a pastebin.
我没有从少数文件中粘贴代码,而是创建了一个包含两个分支的存储库,其中包含完整的 运行 可用示例。
您可以 运行 通过编辑 build.sh
和 run-native.sh
并更改行 jdk="/usr/lib/jvm/java-11-oracle"
以使其对您的系统准确。那么:
./build.sh #compiles the java program and cpp program
./run-native.sh #Sets LD_LIBRARY_PATH and runs the compiled cpp program
or
./run-with-java.sh #only on "withjfx" branch, runs via java at cli.
如您所见,No JavaFX
版本 运行 可以,但 JavaFX
版本仅 运行 通过调用 java
可执行文件,如果通过我的本机启动器执行,它会进行核心转储。
最后,这是我尝试使用本机启动器 运行 JavaFX 版本时得到的转储:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f77513575d8, pid=15281, tid=15301
#
# JRE version: Java(TM) SE Runtime Environment (11.0.1+13) (build 11.0.1+13-LTS)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.0.1+13-LTS, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# j java.util.Arrays$ArrayList.<init>([Ljava/lang/Object;)V+6 java.base@11.0.1
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %d %P" (or dumping to /home/joshua/work/javalaunch/core.15281)
#
# An error report file with more information is saved as:
# /home/joshua/work/javalaunch/hs_err_pid15281.log
Compiled method (c2) 326 208 4 java.util.Objects::requireNonNull (14 bytes)
total in heap [0x00007f7758e10d90,0x00007f7758e10fc8] = 568
relocation [0x00007f7758e10f08,0x00007f7758e10f18] = 16
main code [0x00007f7758e10f20,0x00007f7758e10f60] = 64
stub code [0x00007f7758e10f60,0x00007f7758e10f78] = 24
metadata [0x00007f7758e10f78,0x00007f7758e10f80] = 8
scopes data [0x00007f7758e10f80,0x00007f7758e10f90] = 16
scopes pcs [0x00007f7758e10f90,0x00007f7758e10fc0] = 48
dependencies [0x00007f7758e10fc0,0x00007f7758e10fc8] = 8
Could not load hsdis-amd64.so; library not loadable; PrintAssembly is disabled
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
./run-native.sh: line 6: 15281 Aborted (core dumped) ./bin/launch
根据此处用户的推荐,基于之前的崩溃,我在我的系统上安装了 hsdis-amd64.so 并指向 LD_LIBRARY_PATH
。我仍然得到一个核心转储,看起来它所做的只是让核心转储加载反汇编程序:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f9e6e2015d8, pid=17530, tid=17550
#
# JRE version: Java(TM) SE Runtime Environment (11.0.1+13) (build 11.0.1+13-LTS)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.0.1+13-LTS, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# j java.util.Arrays$ArrayList.<init>([Ljava/lang/Object;)V+6 java.base@11.0.1
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %d %P" (or dumping to /home/joshua/work/so-question/core.17530)
#
# An error report file with more information is saved as:
# /home/joshua/work/so-question/hs_err_pid17530.log
Compiled method (c2) 372 187 4 java.util.Objects::requireNonNull (14 bytes)
total in heap [0x00007f9e75cbb890,0x00007f9e75cbbac8] = 568
relocation [0x00007f9e75cbba08,0x00007f9e75cbba18] = 16
main code [0x00007f9e75cbba20,0x00007f9e75cbba60] = 64
stub code [0x00007f9e75cbba60,0x00007f9e75cbba78] = 24
metadata [0x00007f9e75cbba78,0x00007f9e75cbba80] = 8
scopes data [0x00007f9e75cbba80,0x00007f9e75cbba90] = 16
scopes pcs [0x00007f9e75cbba90,0x00007f9e75cbbac0] = 48
dependencies [0x00007f9e75cbbac0,0x00007f9e75cbbac8] = 8
Loaded disassembler from hsdis-amd64.so
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
./run-native.sh: line 6: 17530 Aborted (core dumped) ./bin/launch
更新:我在 Ubuntu 18.04 和 Windows 7 上重复了这个问题。
我明白了。问题出在第 35 行,参数传递给 JVM 的主要方法:
env->CallStaticVoidMethod( cls, main, " ");
我们正在将 c 字符串传递给 Java,其中 java 期望 java.lang.String[]。一旦有人试图读取该参数,JVM 就会崩溃。 JavaFX 必须在 main 和 start() 之间的某个时刻读取参数,并因此崩溃。
正确的行是
env->CallStaticVoidMethod( cls, main, "(I)V");
(我没有测试过这个,但这是 java 人员提供的示例代码中的公共行)
或:
jclass classString = env->FindClass("java/lang/String");
jobjectArray argsToJava = env->NewObjectArray(0, classString, NULL);
env->CallStaticVoidMethod( cls, main, argsToJava );
我写了一个 C++ JNI Java 启动器。如果我启动一个不使用 JavaFX 的 java 程序,它会工作,但如果我尝试用它启动一个 JavaFX 程序,它会创建一个核心转储。这是代码:
仅当我使用本机启动器时才会发生核心转储。如果我 运行 具有相同参数的 JavaFX 程序在命令行中使用 java
,则没有问题。它 运行 符合预期。
Here's the content of the hs_err file, in a pastebin.
我没有从少数文件中粘贴代码,而是创建了一个包含两个分支的存储库,其中包含完整的 运行 可用示例。
您可以 运行 通过编辑 build.sh
和 run-native.sh
并更改行 jdk="/usr/lib/jvm/java-11-oracle"
以使其对您的系统准确。那么:
./build.sh #compiles the java program and cpp program
./run-native.sh #Sets LD_LIBRARY_PATH and runs the compiled cpp program
or
./run-with-java.sh #only on "withjfx" branch, runs via java at cli.
如您所见,No JavaFX
版本 运行 可以,但 JavaFX
版本仅 运行 通过调用 java
可执行文件,如果通过我的本机启动器执行,它会进行核心转储。
最后,这是我尝试使用本机启动器 运行 JavaFX 版本时得到的转储:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f77513575d8, pid=15281, tid=15301
#
# JRE version: Java(TM) SE Runtime Environment (11.0.1+13) (build 11.0.1+13-LTS)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.0.1+13-LTS, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# j java.util.Arrays$ArrayList.<init>([Ljava/lang/Object;)V+6 java.base@11.0.1
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %d %P" (or dumping to /home/joshua/work/javalaunch/core.15281)
#
# An error report file with more information is saved as:
# /home/joshua/work/javalaunch/hs_err_pid15281.log
Compiled method (c2) 326 208 4 java.util.Objects::requireNonNull (14 bytes)
total in heap [0x00007f7758e10d90,0x00007f7758e10fc8] = 568
relocation [0x00007f7758e10f08,0x00007f7758e10f18] = 16
main code [0x00007f7758e10f20,0x00007f7758e10f60] = 64
stub code [0x00007f7758e10f60,0x00007f7758e10f78] = 24
metadata [0x00007f7758e10f78,0x00007f7758e10f80] = 8
scopes data [0x00007f7758e10f80,0x00007f7758e10f90] = 16
scopes pcs [0x00007f7758e10f90,0x00007f7758e10fc0] = 48
dependencies [0x00007f7758e10fc0,0x00007f7758e10fc8] = 8
Could not load hsdis-amd64.so; library not loadable; PrintAssembly is disabled
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
./run-native.sh: line 6: 15281 Aborted (core dumped) ./bin/launch
根据此处用户的推荐,基于之前的崩溃,我在我的系统上安装了 hsdis-amd64.so 并指向 LD_LIBRARY_PATH
。我仍然得到一个核心转储,看起来它所做的只是让核心转储加载反汇编程序:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f9e6e2015d8, pid=17530, tid=17550
#
# JRE version: Java(TM) SE Runtime Environment (11.0.1+13) (build 11.0.1+13-LTS)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (11.0.1+13-LTS, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# j java.util.Arrays$ArrayList.<init>([Ljava/lang/Object;)V+6 java.base@11.0.1
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/share/apport/apport %p %s %c %d %P" (or dumping to /home/joshua/work/so-question/core.17530)
#
# An error report file with more information is saved as:
# /home/joshua/work/so-question/hs_err_pid17530.log
Compiled method (c2) 372 187 4 java.util.Objects::requireNonNull (14 bytes)
total in heap [0x00007f9e75cbb890,0x00007f9e75cbbac8] = 568
relocation [0x00007f9e75cbba08,0x00007f9e75cbba18] = 16
main code [0x00007f9e75cbba20,0x00007f9e75cbba60] = 64
stub code [0x00007f9e75cbba60,0x00007f9e75cbba78] = 24
metadata [0x00007f9e75cbba78,0x00007f9e75cbba80] = 8
scopes data [0x00007f9e75cbba80,0x00007f9e75cbba90] = 16
scopes pcs [0x00007f9e75cbba90,0x00007f9e75cbbac0] = 48
dependencies [0x00007f9e75cbbac0,0x00007f9e75cbbac8] = 8
Loaded disassembler from hsdis-amd64.so
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
./run-native.sh: line 6: 17530 Aborted (core dumped) ./bin/launch
更新:我在 Ubuntu 18.04 和 Windows 7 上重复了这个问题。
我明白了。问题出在第 35 行,参数传递给 JVM 的主要方法:
env->CallStaticVoidMethod( cls, main, " ");
我们正在将 c 字符串传递给 Java,其中 java 期望 java.lang.String[]。一旦有人试图读取该参数,JVM 就会崩溃。 JavaFX 必须在 main 和 start() 之间的某个时刻读取参数,并因此崩溃。
正确的行是
env->CallStaticVoidMethod( cls, main, "(I)V");
(我没有测试过这个,但这是 java 人员提供的示例代码中的公共行)
或:
jclass classString = env->FindClass("java/lang/String");
jobjectArray argsToJava = env->NewObjectArray(0, classString, NULL);
env->CallStaticVoidMethod( cls, main, argsToJava );