-java.library.path,ld library path

-java.library.path,ld library path,解析java.library.path和LD_LIBRARY_PATH的介绍与区别

这篇文章主要介绍了java.library.path和LD _库_路径的介绍与区别,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

背景

近期要将算法部署到一个机群的虚拟主机(Debian 9.1 gcc 6.3.0)上,采用的是爪哇JNI共享库的方式来完成底层算法能力的部署。

其中需要用到各种第三方库,有从源码编译的,也有直接下载的所以,包括OpenCV相关、张量流相关、MKL以OpenMP相关的动态库。

遇到一个问题,libmklml_intel.so这个库只能放在LD _库_路径中进行加载,而不能通过java.library.path完成加载,所以有必要搞清楚这两个路径究竟有什么区别。

java.library.path

官方文档的定义是:加载库时要搜索的路径列表

从定义我们可以发现,首先是一个列表,也就是说可以包括多个地址,然后这些地址是用来帮助虚拟机(Java虚拟机的缩写)搜索需要加载的库文件的。

设置java.library.path

最简单的办法就是在启动虚拟机(Java虚拟机的缩写)前通过Java-DJ ava。图书馆。路径=指向您的库的路径设置这个全局变量。

作用

那么这个地址具体是如何被使用的呢?

当我们调用System.loadLibrary(libname)时,会调用Runtime.loadLibary,然后调用Java/lang/class loader。加载库。在ClassLoader.loadLibrary中,系统属性java.library.path将会被获取,并用来生成需要加载的库的绝对路径,然后将这个绝对路径传给本地方法来调用dlopen/dlsym并最终加载这个库。

如果加载失败,会根据实际情况返回三个异常值:

安全异常——如果安全管理器存在,并且它的检查链接方法不允许加载指定的动态库

不满意的链接错误如果库不存在

NullPointerException如果libname为空

可以参考OpenJDK的仓库:

静态空加载库(来自类的类,字符串名称,

布尔isAbsolute) {

类加载器加载器=

(fromClass==null)?null:来自类。getclass loader();

if (sys_paths==null) {

usr _ paths=初始化路径(' Java。图书馆。路径’);

sys _ paths=初始化路径(' sun。靴子。图书馆。路径’);

}

if (isAbsolute) {

if (loadLibrary0(fromClass,new File(name))) {

返回;

}

抛出new UnsatisfiedLinkError('无法加载库:‘姓名’);

}

如果(加载器!=null) {

string libfilename=loader。查找库(名称);

if (libfilename!=null) {

文件库文件=新文件(libfilename);

如果(!libfile.isAbsolute()) {

抛出新的UnsatisfiedLinkError(

ClassLoader.findLibrary未能返回绝对路径:" libfilename ");

}

if (loadLibrary0(fromClass,libfile)) {

返回;

}

抛出new UnsatisfiedLinkError('无法加载libfilename);

}

}

for(int I=0;i sys _ paths.lengthi ) {

File libfile=new File(sys _ paths[I],system。地图库名称(name));

if (loadLibrary0(fromClass,libfile)) {

返回;

}

}

如果(加载器!=null) {

for(int I=0;i usr _ paths.lengthi ) {

文件库文件=新文件(usr_paths[i],

系统。地图库名称(name));

if (loadLibrary0(fromClass,libfile)) {

返回;

}

}

}

//哎呀,失败了

抛出new UnsatisfiedLinkError(' Java。图书馆。小路中没有姓名’);

}

LD_LIBRARY_PATH

为了搞清楚这个变量的作用,我们先说明一下Unix操作系统操作系统系统是如何加载动态库的,然后自然就明白为什么要有LD _库_路径以及如何使用了。

动态库如何加载?

在基于GNU glibc的系统上,包括所有的linux系统,启动一个ELF格式的二进制可执行文件,会自动调用加载器加载必要的动态链接库,最简单的可执行文件一般会包含一些系统动态库如libc.so等。在Linux系统中,这个加载器叫做/lib/ld-linux.so.X,这个x是指加载器的版本号。然后,加载程序会找到并加载所需的动态库。

加载器在什么路径下搜索并加载动态库?——/etc/ld.so.conf,其中包括所有。这些文件夹中的conf文件/etc/ld.so.conf.d/*。conf文件,每个文件中都包含特定的动态库搜索路径。conf文件,比如/etc/ld.so.conf.d .它是libc的默认搜索路径,/usr/local/lib,这就是为什么我们可以自动完成加载而不显示使用系统库的声明,也是不同系统编译的库不能通用的可见原因之一,因为不同系统的/usr/local/lib目录中的动态库不一致。

每次启动都要查找所有目录,这显然很愚蠢,所以用/etc/ld.so.cache来缓存路径,并通过ldconfig更新这个缓存路径。有兴趣的可以自行查看这个缓存文件。其实这个缓存路径也很长,基本包括了系统可能存储动态库的路径。

为什么有LD_LIBRARY_PATH?

上面我们说了使用cache和ldconfig可以简化动态库的搜索和加载过程,但是还有两个问题没有考虑到。一是编译后的库没有放入系统目录,二是依赖库数量少,不需要经过这么复杂的查找。

LD_LIBRARY_PATH就是用来满足这个需求的。它还指定了一个搜索路径,ld-linux.so会优先搜索这个路径下需要的动态库。如果找不到,请转到ld.so.conf中指定的目录

使用

导出LD _ LIBRARY _ PATH=路径到库

请务必注意,多个目录之间用以下符号分隔:

区别

前面介绍了Java.library.path和LD_LIBRARY_PATH,都是为了加载所需的动态库。有什么区别?

前者在java环境下调用,设置在jvm启动前生效;后者也是在启动前,不过是在Unix环境下使用。前者是通过修改属性来设置路径;后者是直接添加ld-linux的搜索路径的库,所以对于JNI来说,最好使用前者,对于有多个依赖关系的库,最好使用LD_LIBRARY_PATH。

参考

HowTo:如何为JNI相关库配置库路径

https://zau ner . nllk . net/post/0013-JNI-and-the-Java-library-path/

https://docs . Oracle . com/javase/8/docs/API/Java/lang/system . html # get properties-

https://www . tutorialspoint . com/Java/lang/runtime _ loadlibrary . htm

https://stack overflow . com/questions/27945268/difference-between-using-Java-library-path-and-LD-library-path

关于Linux动态库的文档

关于解析java.library.path和LD_LIBRARY_PATH的介绍和区别,本文到此为止。有关java.library.path和LD_LIBRARY_PATH的更多信息,请搜索我们以前的文章或继续浏览下面的相关文章。希望你以后能支持我们!

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: