`
longgangbai
  • 浏览: 7330639 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Linux下动态共享库加载时遇到的问题解决方案及原理

 
阅读更多

 在java调用jni或者JNA时候,报

      error while loading shared libraries: libprint.so: cannot open shared object file: No such file or directory。这便是典型的找不到动态库的错误.

 

具体说来,动态链接器ld.so按照下面的顺序来搜索需要的动态共享库:

  1.ELF可执行文件中动态段中DT_RPATH所指定的路径。这实际上是通过一种不算很常用,却比较实用的方法所设置的:编译目标代码时,可以对gcc加入链接参数“-Wl,-rpath”指定动态库搜索路径;

  2.环境变量LD_LIBRARY_PATH指定的动态库搜索路径;

  3./etc/ld.so.cache中所缓存的动态库路径(如果支持ld.so.cache的话)。这可以通过修改配置文件/etc/ld.so.conf中指定的动态库搜索路径来改变;

  4.默认的动态库搜索路径/lib;

  5.默认的动态库搜索路径/usr/lib。

  在嵌入式Linux系统的实际应用中,1和2被经常使用,也有一些相对简单的的嵌入式系统会采用4或5的路径来规范动态库。3在嵌入式系统中使用的比较少,因为有很多系统根本就不支持ld.so.cache。

  4和5的方式非常简单,只要将所需要的库放到/lib或/usr/lib就可以解决找不到库的问题,不过对于大一些的系统来说,不太方便管理。1和2的方式要稍微复杂一些。

 

 

         项目中使用到JNI来加载本地库,项目自身(web使用)和对外接口(不是web使用)都用到相同的DLL,当web使用访问正常时,接口访问就报错;相反当接口访问正常时,web使用也会报错。错误信息:java.lang.UnsatisfiedLinkError: Native Library XX.dll already loaded in another。

 

分析:这种错误在我们使用热启动方式发布某个使用了JNI技术的Web应用时,并将调用年native方法的jar包独立部署在该应用下面,当我们的Web应用有了更新以后,在调用到该jar包封装的native方法时,会抛出该错误。(以上OS为Windows,若是Linux或Unix,应该是xxx.so 报错) 这是因为Web服务器已经在第一次加载该应用时,已经load了该dll,当该应用被再次热启动时,该dll将重新被加载,于是报错。解决方案: 一、将含有JNI调用的jar包部署在Web服务器的公用lib库中。Web应用再发布时可以不用加载;二、jar包部署不变,在该Web中实现一个listener,监听是否第一次启动,若不是第一次启动,屏蔽掉该jar包所含dll的加载。

 

1、原因

        查询资料后才得知:Java虚拟机为了在JNI本地库中确保基于classloader的命名空间隔离,因而不允许一个JNI本地库被两个不同的classloader加载。而JBoss中web应用的classloader是独立的,也就是说每个web应用都有一个专属的classloader,这样就出现两个classloader加载同一JNI本地库的情况。

 

 

 

2、解决方法

         解决这个问题其实很简单,将访问到jni的代码单独提取出来,并不直接让项目自身的classLoader加载,则是让其由systemLoader加载 即可。一种方法就是将这部分代码,单独封装成一个jar,放到java的systemLoader可以加载的地方,如lib/ext目录下。然后,项目中 仍然去调用此代码。由于访问dll的代码由systemLoader加载,因此,多个项目同时访问同一个dll时,即可避免再次加载了。因为,第二个项目 在访问时,寻找到的类,已经被systemLoader加载过了,因此项目本身的classLoader就不会再去加载这个类了。

        在Weblogic中,虽然不同的web应用使用不同的classloader,但是web应用classloader的父classloader是相同的,这样根据双亲委托模型只要让父classloader加载JNI本地库就可以避免被多个classloader加载。将so放在共享目录(System.getProperty("java.library.path"))的lib目录的并采用System.loadLibrary(libName)即可。

重新Weblogic问题就可以解决。

 

HPUX环境,在WebLogic服务器中使用java调用C动态连接库异常问题总结

 

总结1:查看服务器环境变量是否设置

       SHLIB_PATH此环境变量设置为HPUX默认的查找路径,配置为动态连接库的路径。

       LD_LIBRARY_PATH此为LINUX设置的路径。

 

注意:

       此环境变量不一定非得设置,可以用java.library.path来查看当前的路径指向哪里,可以将动态连接库拷到java.library.path指定的目录即可。

 

总结2:查看so文件是否有启动权限,如果没有则会报权限问题。

       测试方法:可以使用System.loadLibrary(“XXXXX.so”)来进行测试,如果正常通过则无异常显示,如果有异常,则根据提示来进行相应的更改。

       测试时会提示是不在路径中,还是别的什么异常。

 

 基础知识:

UnsatisfiedLinkError

在把本机调用链接到对应的本机定义时,类装入器扮演着重要角色。如果程序试图装入一个不存在或者放错的本机库时,在链接阶段的解析过程会发生 UnsatisfiedLinkError。JVM 规范指定 UnsatisfiedLinkError 是:

对于声明为 native 的方法,如果 Java 虚拟机找不到和它对应的本机语言定义,就会抛出该异常。 当调用本机方法时,类装入器会尝试装入定义了该方法的本机库。如果找不到这个库,就会抛出这个错误。

本机库的装入由调用 System.loadLibrary() 方法的类的类装入器启动 —— 在清单 6 中,就是 UnsatisfiedLinkErrorTest 的类装入器。根据使用的类装入器,会搜索不同的位置:

  • 对于由 bootstrap 类装入器装入的类,搜索 sun.boot.library.path
  • 对于由扩展类装入器装入的类,先搜索 java.ext.dirs,然后是 sun.boot.library.path,然后是 java.library.path
  • 对于由系统类装入器装入的类,搜索 sun.boot.library.path,然后是 java.library.path

在清单 6 中,UnsatisfiedLinkErrorTest 类是由系统类装入器装入的。要装入所引用的本机库,这个类装入器先查找 sun.boot.library.path,然后查找 java.library.path。因为在两个位置中都没有需要的库,所以类装入器抛出 UnsatisfiedLinkageError

 

System.loadLibrary()的使用方法汇总

当使用System.loadLibrary()调用 Dll,两种方法:

1.设定环境变量。

比如:所编辑的Dll在目录“D:/cppProjects/nativecode/release”内,将这个路径复制添加到电脑的环境变量中的path变量内即可。

2.设定项目属性。(开发推荐)

右击项目名|选择属性properties|在左边列表内选择“Java Build Path”|在右边选项卡用选择“source”|点开项目名前的“+”号,选择“Native library location”,“Edit”选择上面“D:/cppProjects/nativecode/release”路径。(当然如果将dll拷贝到workspace下也可以用相对路径。也可右击“src”设定其properties内Native Library项。)

 

 

System.load 和 System.loadLibrary详解

1.它们都可以用来装载库文件,不论是JNI库文件还是非JNI库文件。在任何本地方法被调用之前必须先用这个两个方法之一把相应的JNI库文件装载。

2.System.load 参数为库文件的绝对路径,可以是任意路径。
例如你可以这样载入一个windows平台下JNI库文件:
System.load("C://Documents and Settings//TestJNI.dll");。

3. System.loadLibrary 参数为库文件名,不包含库文件的扩展名。
例如你可以这样载入一个windows平台下JNI库文件
System. loadLibrary ("TestJNI");

这里,TestJNI.dll 必须是在java.library.path这一jvm变量所指向的路径中。
可以通过如下方法来获得该变量的值:
System.getProperty("java.library.path");
默认情况下,在Windows平台下,该值包含如下位置:
1)和jre相关的一些目录
2)程序当前目录
3)Windows目录
4)系统目录(system32)
5)系统环境变量path指定目录

4.如果你要载入的库文件静态链接到其它动态链接库,例如TestJNI.dll 静态链接到dependency.dll, 那么你必须注意:
1)如果你选择
System.load("C://Documents and Settings// TestJNI.dll");
那么即使你把dependency.dll同样放在C://Documents and Settings//下,load还是会因为找不到依赖的dll而失败。因为jvm在载入TestJNI.dll会先去载入TestJNI.dll所依赖的库文件dependency.dll,而dependency.dll并不位于java.library.path所指定的目录下,所以jvm找不到dependency.dll。
你有两个方法解决这个问题:一是把C://Documents and Settings//加入到java.library.path的路径中,例如加入到系统的path中。二是先调用
System.load("C://Documents and Settings// dependency.dll"); 让jvm先载入dependency.dll,然后再调用System.load("C://Documents and Settings// TestJNI.dll");
2)如果你选择
System. loadLibrary ("TestJNI");
那么你只要把dependency.dll放在任何java.library.path包含的路径中即可,当然也包括和TestJNI.dll相同的目录。

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    linux 动态库静态库

    通过压缩包中的"linux动态库及静态库的创建和使用"文件,你可以找到更具体的实践教程和示例代码,包括如何创建、链接和使用这两种类型的库,以及解决可能出现的问题。这些资料将帮助你深入理解和掌握Linux环境下的...

    Linux静态库和动态库的制作和使用(ubuntu18.04)以及解决动态库加载失败问题

    使用静态库和动态库时,需要在编译程序时通过`-l`标志指定库名,例如`gcc main.c -lmylib`。对于动态库,如果出现加载失败的问题,可能的原因包括: 1. 动态库文件不在系统的搜索路径中。 2. 库版本不匹配,程序...

    Linux下使用动态库小结

    本文旨在介绍Linux下动态库的基础知识及其使用方法。 **1.1 静态库与动态库的区别** - **静态库**: 在编译链接阶段,静态库中的代码会被复制到可执行文件中,成为可执行文件的一部分。这意味着使用静态库编译的...

    嵌入式系统/ARM技术中的Linux下动态共享库加载时的搜索路径详解

    然而,对于不熟悉动态库加载机制的开发者来说,遇到“error while loading shared libraries”这样的错误是常见的。这通常是由于动态链接器ld.so无法在正确的搜索路径中找到所需的库文件。 动态链接器ld.so遵循一定...

    Windows和Linux动态库

    Linux动态库的工作原理类似,但其加载和管理机制略有不同。动态库的加载由ld.so动态链接器处理,可以通过ldd命令查看程序依赖的库。Linux下,动态库的调用也是静态和动态两种方式: - 静态调用:编译时通过-L和-l...

    预加载共享动态链接库算法在桌面Linux环境下的设计与实现.pdf

    《预加载共享动态链接库算法在桌面Linux环境下的设计与实现》这篇论文主要探讨了如何在Linux桌面环境中通过预加载共享动态链接库(Shared Dynamic Linking Libraries)来优化系统性能,提升用户体验。针对Linux操作...

    Linux寄生程序加载动态库的研究与实现.pdf

    为了解决这些问题,论文提出了一个新的方法,即利用Linux的proc文件系统来动态加载和调用宿主程序未加载的动态库。proc文件系统提供了一个虚拟文件系统,可以用来获取系统状态和控制进程。通过proc文件系统,寄生...

    Linux下动态链接库加载路径及搜索路径问题

    本文将深入探讨Linux下动态链接库的加载路径和搜索路径问题。 首先,当一个ELF(Executable and Linkable Format)格式的可执行文件尝试运行时,如果它依赖于动态链接库,系统会按照一定的顺序查找这些库。这一搜索...

    libsrc.rar_linux 动态库

    标题"libsrc.rar_linux 动态库"表明这个压缩包包含了关于Linux环境下动态库的示例和相关资料。这可能包括如何创建、链接以及使用动态库的实践教程。 动态库的扩展名通常是`.so`,例如`libmylib.so`。在Linux下,...

    linux创建和使用动态链接库.so文件

    通过以上步骤,你已经掌握了如何在 Linux 下创建和使用动态链接库 `.so` 文件的基本方法。这些技能对于开发复杂的软件项目尤其有用,因为它们允许你轻松地管理不同组件之间的依赖关系,并提高代码的可重用性。

    Linux程序运行时加载动态库失败的解决方法

    本文将探讨几种解决Linux程序运行时加载动态库失败的方法。 首先,当遇到“error while loading shared libraries: libmfs_open.so: cannot open shared object file: No such file or directory”这样的错误时,...

    安装linux的so库

    ### 安装Linux的SO库及解决libz.so.1缺失问题 在Linux环境中,动态链接库(Dynamic Link Library,简称DLL,在Linux中通常被称为共享对象文件或.so文件)是程序运行时依赖的重要组成部分。当遇到类似“找不到libz....

    linux下编译.so库文件

    掌握这些知识不仅能够帮助开发者构建更高效、更易于维护的软件,还能在遇到具体问题时,提供解决问题的新思路和方法。无论是对于初学者还是经验丰富的开发者,理解和熟练运用Linux下的库文件编译技术都是至关重要的...

    基于Linux共享库注射技术的网络诱骗系统设计.pdf

    Linux共享库注射技术是一种动态链接技术,可以在运行时加载共享库,从而实现对系统的控制。通过使用该技术,可以在不影响系统正常运行的情况下,对入侵者的行为进行跟踪和监视,从而捕获其数据。 在设计网络诱骗...

    windows和linux下生成动态库的cmake示例

    动态库(也称为DLLs在Windows上,共享对象或SOs在Linux上)是在程序运行时加载的代码库,而不是在编译时链接到可执行文件中。这种方式有助于节省磁盘空间和内存,因为多个程序可以共享同一份库的副本。 在Windows...

    基于Virtual PC平台部署Linux疑难问题及解决方案.pdf

    【基于Virtual PC平台部署Linux疑难问题及解决方案】 随着信息技术的快速发展,Linux操作系统因其开源和出色的稳定性,被越来越多的用户用于学习、应用和开发。Virtual PC作为一款实用的虚拟机平台软件,为用户提供...

    coredump问题原理探究-Linux x86版.rar

    本资料"coredump问题原理探究-Linux x86版"聚焦于Linux环境下,特别是x86架构下的核心转储文件分析,旨在帮助开发者深入理解core dump的工作机制,并提供有效的定位和解决问题的方法。 一、core dump的基本概念 1. ...

    Linux动态链接库.so文件的创建与使用

    使用动态链接库时,程序在运行时会查找相应的`.so`文件。如果找不到,可能会出现`libnotfound`错误。解决方法包括检查`LD_LIBRARY_PATH`,确保库文件的路径正确,或者在系统配置文件`/etc/ld.so.conf`中添加库路径。...

    liunx静态库与动态库链接装载与库.zip

    程序员的自我修养—链接、装载与库.pdf这本书详细介绍了这些概念和技术,包括链接器的工作原理、装载器的行为、静态库与动态库的创建和使用,以及解决链接和装载问题的方法。通过深入理解这些内容,开发者可以更有效...

Global site tag (gtag.js) - Google Analytics