热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

解析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 

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内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 如何将CentOS8转换为CentOSStream
    CentOS Stream是一个持续交付的Linux发行版,它在RHEL之前处于领先地位。它将具有滚动发布,即不断进行更改。CentOS将成为一个上游版本,它将具有测试补丁和更新。 ... [详细]
  • 系统安装Debian系统的安装方式和Ubuntu系统的安装方式几乎是一样的,毕竟Ubuntu系统是基于Debian的,就如同CentOS基于Redhat ... [详细]
  • 阿里Treebased Deep Match(TDM) 学习笔记及技术发展回顾
    本文介绍了阿里Treebased Deep Match(TDM)的学习笔记,同时回顾了工业界技术发展的几代演进。从基于统计的启发式规则方法到基于内积模型的向量检索方法,再到引入复杂深度学习模型的下一代匹配技术。文章详细解释了基于统计的启发式规则方法和基于内积模型的向量检索方法的原理和应用,并介绍了TDM的背景和优势。最后,文章提到了向量距离和基于向量聚类的索引结构对于加速匹配效率的作用。本文对于理解TDM的学习过程和了解匹配技术的发展具有重要意义。 ... [详细]
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Webmin远程命令执行漏洞复现及防护方法
    本文介绍了Webmin远程命令执行漏洞CVE-2019-15107的漏洞详情和复现方法,同时提供了防护方法。漏洞存在于Webmin的找回密码页面中,攻击者无需权限即可注入命令并执行任意系统命令。文章还提供了相关参考链接和搭建靶场的步骤。此外,还指出了参考链接中的数据包不准确的问题,并解释了漏洞触发的条件。最后,给出了防护方法以避免受到该漏洞的攻击。 ... [详细]
  • Linux磁盘的分区、格式化的观察和操作步骤
    本文介绍了如何观察Linux磁盘的分区状态,使用lsblk命令列出系统上的所有磁盘列表,并解释了列表中各个字段的含义。同时,还介绍了使用parted命令列出磁盘的分区表类型和分区信息的方法。在进行磁盘分区操作时,根据分区表类型选择使用fdisk或gdisk命令,并提供了具体的分区步骤。通过本文,读者可以了解到Linux磁盘分区和格式化的基本知识和操作步骤。 ... [详细]
  • Ubuntu 9.04中安装谷歌Chromium浏览器及使用体验[图文]
    nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ... [详细]
  • imx6ull开发板驱动MT7601U无线网卡的方法和步骤详解
    本文详细介绍了在imx6ull开发板上驱动MT7601U无线网卡的方法和步骤。首先介绍了开发环境和硬件平台,然后说明了MT7601U驱动已经集成在linux内核的linux-4.x.x/drivers/net/wireless/mediatek/mt7601u文件中。接着介绍了移植mt7601u驱动的过程,包括编译内核和配置设备驱动。最后,列举了关键词和相关信息供读者参考。 ... [详细]
  • CentOS7.8下编译muduo库找不到Boost库报错的解决方法
    本文介绍了在CentOS7.8下编译muduo库时出现找不到Boost库报错的问题,并提供了解决方法。文章详细介绍了从Github上下载muduo和muduo-tutorial源代码的步骤,并指导如何编译muduo库。最后,作者提供了陈硕老师的Github链接和muduo库的简介。 ... [详细]
  • 通过Anaconda安装tensorflow,并安装运行spyder编译器的完整教程
    本文提供了一个完整的教程,介绍了如何通过Anaconda安装tensorflow,并安装运行spyder编译器。文章详细介绍了安装Anaconda、创建tensorflow环境、安装GPU版本tensorflow、安装和运行Spyder编译器以及安装OpenCV等步骤。该教程适用于Windows 8操作系统,并提供了相关的网址供参考。通过本教程,读者可以轻松地安装和配置tensorflow环境,以及运行spyder编译器进行开发。 ... [详细]
  • docker安装到基本使用
    记录docker概念,安装及入门日常使用Docker安装查看官方文档,在"Debian上安装Docker",其他平台在"这里查 ... [详细]
  • Win10+Python3.7+Tensorflow安装
    Win10+Python3.7+Tensorflow安装Step1:安装AnacondaStep2:Tensorflow的安装转载请注明出处:https:blog.csdn.net ... [详细]
  • 干货 | 携程AI推理性能的自动化优化实践
    作者简介携程度假AI研发团队致力于为携程旅游事业部提供丰富的AI技术产品,其中性能优化组为AI模型提供全方位的优化方案,提升推理性能降低成本࿰ ... [详细]
  • 如何查看电脑系统版本_腾讯云服务器系统版本怎么看?Windows和Centos版本怎么选?...
    腾讯云服务器系统版本怎么看?想要知道自己的腾讯云服务器系统版本是哪个,可以登录云服务器后台管理系统查看,或者使用命令行查询,如果不会操作& ... [详细]
author-avatar
firespace
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有