主页 > Java教程 > java.library.path和LD_LIBRARY_PATH

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

  • 更新时间:
  • 编辑:郭飞羽
  • 1536人关注

这篇文章主要介绍了java.library.path和LD_LIBRARY_PATH的介绍与区别,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下,另外这篇文章主要知识点是关于java.library.path、java、LD_LIBRA、java.library.path和LD_LIBRARY_PATH的内容,如果大家想对相关知识点有系统深入的学习,可以参阅以下电子资料:

参考资料
资料:
Java性能调优指南
大小:
42.6MB
类别:
Java调优指南电子资源立即下载

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

小编给大家总结一篇《解析java.library.path和LD_LIBRARY_PATH的介绍与区别》的技术内容,觉得有用就收藏了,重新编辑了一下发到本站,为了方便大家的阅读。

背景

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

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

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

java.library.path

官方文档的定义是:List of paths to search when loading libraries
从定义我们可以发现,首先是一个list,也就是说可以包括多个地址,然后这些地址是用来帮助jvm搜索需要加载的库文件的。

设置java.library.path

最简单的办法就是在启动jvm前通过java -Djava.library.path=path-to-your-libs设置这个全局变量。

作用

那么这个地址具体是如何被使用的呢?
当我们调用System.loadLibrary(libname)时,会调用Runtime.loadLibary,然后调用java/lang/ClassLoader.loadLibrary。在ClassLoader.loadLibrary中,系统属性java.library.path将会被获取,并用来生成需要加载的库的绝对路径,然后将这个绝对路径传给本地方法来调用dlopen/dlsym并最终加载这个库。
如果加载失败,会根据实际情况返回三个异常值:

SecurityException − if a security manager exists and its checkLink method doesn't allow loading of the specified dynamic library
UnsatisfiedLinkError − if the library does not exist
NullPointerException − if libname is null

可以参考OpenJDK的仓库:

static void loadLibrary(Class fromClass, String name,
                            boolean isAbsolute) {
        ClassLoader loader =
            (fromClass == null) ? null : fromClass.getClassLoader();
        if (sys_paths == null) {
            usr_paths = initializePath("java.library.path");
            sys_paths = initializePath("sun.boot.library.path");
        }
        if (isAbsolute) {
            if (loadLibrary0(fromClass, new File(name))) {
                return;
            }
            throw new UnsatisfiedLinkError("Can't load library: " + name);
        }
        if (loader != null) {
            String libfilename = loader.findLibrary(name);
            if (libfilename != null) {
                File libfile = new File(libfilename);
                if (!libfile.isAbsolute()) {
                    throw new UnsatisfiedLinkError(
    "ClassLoader.findLibrary failed to return an absolute path: " + libfilename);
                }
                if (loadLibrary0(fromClass, libfile)) {
                    return;
                }
                throw new UnsatisfiedLinkError("Can't load " + libfilename);
            }
        }
        for (int i = 0 ; i < sys_paths.length ; i++) {
            File libfile = new File(sys_paths[i], System.mapLibraryName(name));
            if (loadLibrary0(fromClass, libfile)) {
                return;
            }
        }
        if (loader != null) {
            for (int i = 0 ; i < usr_paths.length ; i++) {
                File libfile = new File(usr_paths[i],
                                        System.mapLibraryName(name));
                if (loadLibrary0(fromClass, libfile)) {
                    return;
                }
            }
        }
        // Oops, it failed
        throw new UnsatisfiedLinkError("no " + name + " in java.library.path");
    }

LD_LIBRARY_PATH

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

动态库如何加载?

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

加载器在什么路径中搜索和加载动态库呢——/etc/ld.so.conf,这个文件会包括/etc/ld.so.conf.d/*.conf这些文件夹中所有的.conf文件,而具体的动态库搜索路径,就包含在每个.conf文件中,比如/etc/ld.so.conf.d/libc.conf,它是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中指定的目录寻找。

使用

export LD_LIBRARY_PATH=paths-to-libs

需要注意的一点是,多个目录是通过:隔开的

区别

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

前者是在java环境中调用,在jvm启动前设置生效;后者也是在启动前,但是是在Unix环境中使用前者是通过修改property来设置路径;后者是直接增加了ld-linux.so的搜索路径对于JNI直接调用的库,最好使用前者,对于有多重依赖关系的库,最好使用LD_LIBRARY_PATH

参考

HowTo: How to configure library path for JNI dependent libraries
https://zauner.nllk.net/post/0013-jni-and-the-java-library-path/
https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getProperties–
https://www.tutorialspoint.com/java/lang/runtime_loadlibrary.htm
https://stackoverflow.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内容请搜索java学习网以前的文章或继续浏览下面的相关文章希望大家以后多多支持java学习网!

相关内容

  • Java集合遍历的实现方法及泛型通配实例分析

    Java集合遍历的实现方法及泛型通配实例分析

    这篇文章主要介绍了Java集合遍历实现方法及泛型通配,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    05-21

    阅读更多
  • java操作elasticsearch的原理及代码

    这篇文章主要介绍了java操作elasticsearch的案例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

    05-30

    阅读更多
  • Java transient 关键字作用及用法

    Java transient 关键字作用及用法

    这篇文章主要介绍了Java transient 关键字是干啥的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    05-21

    阅读更多
  • java编程语言的用途有哪些

    JAVA已经成为应用相当广泛的一种编程语言,那么java语言的主要用途有哪些呢?下面就随码农之家java学院小编一起来看看。

    05-28

    阅读更多
  • Java农夫过河问题的继承与多态实现

    Java农夫过河问题的继承与多态实现

    这篇文章主要介绍了Java农夫过河问题的继承与多态实现详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    05-26

    阅读更多
  • Java基础之引用相关知识总结

    今天聊聊Java的引用,大多数时候我们说引用都是强引用,只有在对象不使用的情况下才会释放内存,其实Java 内存有四种不同的引用.一起看看吧,,需要的朋友可以参考下

    06-19

    阅读更多
  • Java中事件处理与异常处理机制详解

    这篇文章主要介绍了Java中的事件处理与异常处理机制,讲解Java是如何对事件或者异常作出响应以及定义异常的一些方法,需要的朋友可以参考下

    08-24

    阅读更多

知识点补充

小编:孔祺然 10小时1分钟前编辑补充

每天学Java!一分钟了解JRE与JDK

: Java的源代码是以*.java的纯文本文件,可以使用任何文本编辑器来进行编写,但是这个源代码是无法执行的。执行源代码的这个任务就需要JDK和JRE。 JDK 是Java语言的开发包,它可以将*.java结尾的文件编译为可以执行的Java程序。那么,有了可以执行的Java程序,则需要一个JVM才可以将这个Java程序运行起来。而Java运行环境,也就是JRE中包含了JVM。JVM就是Java的虚拟机。最后,JDK中包含了JRE。有了这样一个逻辑基础,下面,我们来分别认识JRE和JDK. 我们先来看一下 JRE 。JRE是英文Java Runtime Environment的缩写,是指Java运行环境。它是面向Java程序的使用者,而不是开发者。它是运行Java程序所必须的环境的集合,包含……

小编:廖素欣 12小时42分钟前编辑补充

学习Java编程语言码农之家带我走进成功捷径

: 从我开始在 “www.javaxue.com”学习Jav a的这段时间里,我心里对Java的认识经历着很大的变化,从一个很模糊的概念,逐渐的变得清晰,所以一直努力的学习着。 在我学习的期间,很多人对我的学习都有很大的帮助,班里的同学们,老师们,每次我在遇到问题的时候,都能找到能帮助我的人。但是,我认为有些东西还是要自己去琢磨,去思考,去想。这样才能不断的进步。 学习Java就是件耗时间的事儿,如果你不肯投入自己的时间,根本不可能在短时间就把Java给学好了,原本我对Java接触了时间就比较短,如果还不努力的话,根本就不能在几个月内把这些知识都掌握了,所以我就只能坐在电脑前,敲着那些……