问题描述
我用Java开发了一个应用程序,该应用程序使用JNA加载了C ++共享库.详细过程如下.
I develop an app in java that loads a C++ shared library using JNA. The detailed procedure is the following.
- 在罐子中查找库
- 将
System.load( C_LIBRARY_PATH )
与步骤1的结果一起使用 - 使用JNA工具加载库:
Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
- Find library in the jar
- use
System.load( C_LIBRARY_PATH )
with the result of step 1 - Load library using JNA tools:
Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
此过程用于创建c ++库的包装,因此会生成用于其他项目的java库.第1点和第2点的灵感来自 adamheinrich 的工作.在调用load
函数之前,将检查文件是否存在.
This procedure is used to create a wrapper of the c++ library and hence produces a java library that is used for other projects. Point 1 and 2 are inspired by the work of adamheinrich. The existence of the file is checked before calling the load
function.
在项目中使用Java包装器时,我会随机出现如下错误.您能指导我进行调试并尝试控制这种随机故障吗?
When using the java wrapper in a project I randomly have an error like below. Could you guide me in debugging and try to control this random failure?
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007ff754e1cf9b, pid=8922, tid=9159
#
# JRE version: OpenJDK Runtime Environment (10.0.1+10) (build 10.0.1+10)
# Java VM: OpenJDK 64-Bit Server VM (10.0.1+10, mixed mode, tiered, compressed oops, g1 gc, linux-amd64)
# Problematic frame:
# C [libc.so.6+0x15cf9b] __memmove_avx_unaligned_erms+0x8b
#
# Core dump will be written. Default location: Core dumps may be processed with "/usr/lib/systemd/systemd-coredump %P %u %g %s %t %c %h %e" (or dumping to /home/core.8922)
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
--------------- S U M M A R Y ------------
Command Line: -Drebel.base=/home/.jrebel -Drebel.env.ide.plugin.version=2018.1.2 -Drebel.env.ide.version=2018.1 -Drebel.env.ide.product=IU -Drebel.env.ide=intellij -Drebel.notification.url=http://localhost:17434 -agentpath:/home/.IntelliJIdea2018.1/config/plugins/jr-ide-idea/lib/jrebel6/lib/libjrebel64.so -Dvisualvm.id=1716948864493 -Dmaven.multiModuleProjectDirectory=/home/ -Dmaven.home=/home/Documents/ideaIU-2018.1/idea-IU-181.4203.550/plugins/maven/lib/maven3 -Dclassworlds.conf=/home/Documents/ideaIU-2018.1/idea-IU-181.4203.550/plugins/maven/lib/maven3/bin/m2.conf -javaagent:/home/ideaIU-2018.1/idea-IU-181.4203.550/lib/idea_rt.jar=36953:/home/ideaIU-2018.1/idea-IU-181.4203.550/bin -Dfile.encoding=UTF-8 org.codehaus.classworlds.Launcher -Didea.version=2018.1 -P tomcat clean tomcat7:run -f pom.xml
Host: Intel(R) Core(TM) i7-6560U CPU @ 2.20GHz, 4 cores, 15G, Fedora release 28 (Twenty Eight)
Time: Wed Jun 27 08:35:16 2018 CEST elapsed time: 140 seconds (0d 0h 2m 20s)
--------------- T H R E A D ---------------
Current thread (0x00007ff74efc1000): JavaThread "http-bio-8080-exec-7" daemon [_thread_in_native, id=9159, stack(0x00007ff694588000,0x00007ff694689000)]
Stack: [0x00007ff694588000,0x00007ff694689000], sp=0x00007ff694683ae8, free space=1006k
Native frames: (J=compiled Java code, A=aot compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libc.so.6+0x15cf9b] __memmove_avx_unaligned_erms+0x8b
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j java.lang.ClassLoader$NativeLibrary.load0(Ljava/lang/String;Z)Z+0 [email protected]
j java.lang.ClassLoader$NativeLibrary.load()Z+63 [email protected]
j java.lang.ClassLoader$NativeLibrary.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)Z+239 [email protected]
j java.lang.ClassLoader.loadLibrary0(Ljava/lang/Class;Ljava/io/File;)Z+46 [email protected]
j java.lang.ClassLoader.loadLibrary(Ljava/lang/Class;Ljava/lang/String;Z)V+50 [email protected]
j java.lang.Runtime.load0(Ljava/lang/Class;Ljava/lang/String;)V+77 [email protected]
j java.lang.System.load(Ljava/lang/String;)V+7 [email protected]
j *hiddenPackageName*.NativeUtils.loadLibraryFromJar(Ljava/lang/String;Ljava/lang/Class;)V+359
j *hiddenPackageName*.LibraryInitializer.<clinit>()V+13
v ~StubRoutines::call_stub
为了全面概述该问题,我复制了以下过程的第1点和第2点的代码:
In order to give full overview of the issue I copy the code of points 1 and 2 of the procedure below:
public static <T> void loadLibraryFromJar(String path, Class<T> clazz) throws IOException {
if( !path.startsWith( "/" ) ){
throw new IllegalArgumentException( "The path has to be absolute (start with '/')." );
}
// Obtain filename from path
String[] parts = path.split( "/" );
String filename = (parts.length > 1) ? parts[parts.length - 1] : null;
// Split filename to prefix and suffix (extension)
String prefix = "";
String suffix = null;
if( filename != null ){
parts = filename.split( "\\.", 2 );
prefix = parts[0];
suffix = (parts.length > 1) ? "." + parts[parts.length - 1] : null; // Thanks, davs! :-)
}
// Check if the filename is okay
if( filename == null || prefix.length() < 3 ){
throw new IllegalArgumentException( "The filename has to be at least 3 characters long." );
}
// Prepare temporary file
File temp = File.createTempFile( prefix, suffix );
temp.deleteOnExit();
if( !temp.exists() ){
throw new FileNotFoundException( "File " + temp.getAbsolutePath() + " does not exist." );
}
// Prepare buffer for data copying
byte[] buffer = new byte[1024];
int readBytes;
// Open and check input stream
try( InputStream is = clazz.getResourceAsStream( path ) ){
if( is == null ){
throw new FileNotFoundException( "File " + path + " was not found inside JAR." );
}
// Open output stream and copy data between source file in JAR and the temporary file
try( OutputStream os = new FileOutputStream( temp ) ){
while( (readBytes = is.read( buffer )) != -1 ){
os.write( buffer, 0, readBytes );
}
}
}
// Finally, load the library
System.load( temp.getAbsolutePath() );
}
修改:temp.getAbsolutePath()
的值随后等于:
/tmp/libgcc_s7394566251608466486.so.1
/tmp/libgomp14105897271936182307.so.1
/tmp/libpthread18366551914953688272.so.0
/tmp/libstdc++3062153806840733749.so.6
/tmp/libfitting1621020429668741777.so.1.0
推荐答案
我不小心在多个Java类中两次加载了相同的库.更准确地说,调用Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
是在嵌套接口中完成的,我在使用同一c ++库的所有不同对象中复制了该接口.如@cubrr所提醒,这是在第一个对象实例化时静态完成的.因此,该库被多次加载.下面的伪代码说明了我的错误.
I was accidentally loading twice the same library in multiple java classes. More precisely, the call Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
was done in a nested interface that I replicated in all the different objects that were using the same c++ library. This, as reminded by @cubrr, is done statically at instantiation of the first object. Hence the library was loaded multiple times. Below a speudo-code illustrating my mistake.
class A {
protected interface Wrapper extends Library {
Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
double functionA();
}
public double callA() {
return Wrapper.INSTANCE.functionA();
}
}
class B {
protected interface Wrapper extends Library {
Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
double functionB();
}
public double callB() {
return Wrapper.INSTANCE.functionB();
}
}
应该这样做
class Parent {
protected interface Wrapper extends Library {
Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
double functionA();
double functionB();
}
}
class A extends Parent {
public double callA() {
return Wrapper.INSTANCE.functionA();
}
}
class B extends Parent {
public double callB() {
return Wrapper.INSTANCE.functionB();
}
}
这篇关于JNA Native.loadLibrary生成内存故障:__memmove_avx_unaligned_erms的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!