关于java加载dll文件

system.loadlibrary中UnsatisfiedLinkError问题解决,有需要的朋友可以参考下。


最近项目中用到了Jni,需要用java调用Opencv生成的dll文件完成图像处理。


问题描述: UnsatisfiedLinkError:no msvcp120d in java.library.path
dll文件是同事提供的,他同时提供了一个demo project。最初是直接报错:java.lang.UnsatisfiedLinkError: no msvcp120d in java.library.path,这个原因很简单,没有导入相应的依赖库。

解决方案:
使用软件dependencywalker可以查看一个dll所有依赖的dll文件,查看后是一些opencv相关的dll库,导入后问题会解决。

注意事项:

一、首先要明白System.loadlibrary(),还有它和System.load()的区别


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");

4.TestJNI.dll 必须是在java.library.path这一jvm变量所指向的路径中。

可以通过如下方法来获得该变量的值:

System.getProperty("java.library.path");

默认情况下,在Windows平台下,该值包含如下位置:

1)和jre相关的一些目录

2)程序当前目录

3)Windows目录

4)系统目录(system32)

5)系统环境变量path指定目录

5.如果你要载入的库文件静态链接到其它动态链接库,例如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相同的目录。

综上所述,因为我已经调用System.loadLibrary("javaCallcpp"),所以我需要做的就是把其他的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项。)
问题描述:UnsatisfiedLinkError: com.ibm.isbtest.Java2cpp.Contour
由于同时的Java2cpp是在默认包中,现在虽然可以执行,但是不能import到其他的类中,所以我放到了一个其他包中,然后就报这个错了,查了下原因是找不到这个方法,这个很奇怪,网上讲这个问题大部分是因为生成dll时候编译器的问题,比如gcc、mingw中的设置,使用vs重新生成就好了,但是和我的情况不同,我的是确实可以调用成功,只不过是换了一个包

解决方案:

最后在一个评论中找到原因了:有的时候没有注意包名,就是在生生成DLL的时候,javah ***.class这个类里是有包名的,于是生成的DLL也只能在那个包名下那个名字的类里使用了。这个DLL是不能随便放到其他类里用的。

解决方案:使用默认包中的类

从 J2SE 1.4 开始,Java 编译器不再支持 import 进未命包名的类、接口。 详见 J2SE 1.4 与 J2SE 1.3 兼容性文档,第 8 点第二部分:http://java.sun.com/javase/compatibility_j2se1.4.html。而至于为什么 unnamed package 还没有被去除掉?因为这可以很方便地编写一些小程序,也可以方便初学者进行学习。

但是,使用还是可以的,就是使用反射,比如:




在默认包里有个类:




public class DefaultPackage {  
    public void disp() {  
        System.out.println("Hello World!");  
    }  
}



而如果你想再包test下的类中调用disp()方法可以这样:



package test;  

import java.lang.reflect.*;  
public class TestDefaultPackage {  
    public static void main(String[] args) throws Exception {  
        Class c = Class.forName("DefaultPackage");  
        Method m = c.getDeclaredMethod("disp", null);  
        m.invoke(c.newInstance(), null);  
    }  
}


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

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

演示了抛出 UnsatisfiedLinkError 的测试用例 :

UnsatisfiedLinkError.java

public class UnsatisfiedLinkErrorTest {
	public native void call_A_Native_Method();

	static {
		System.loadLibrary("myNativeLibrary");
	}

	public static void main(String[] args) {
		new UnsatisfiedLinkErrorTest().call_A_Native_Method();
	}
}
这段代码调用本机方法 call_A_Native_Method(),该方法是在本机库 myNativeLibrary 中定义的。因为这个库不存在,所以在程序运行时会发生以下错误:

The java class could not be loaded. java.lang.UnsatisfiedLinkError:

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

对于由 bootstrap 类装入器装入的类,搜索 sun.boot.library.path。

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

对于由系统类装入器装入的类,搜索 sun.boot.library.path,然后是 java.library.path。

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

综上所述:

1unsatisfiedlinkError:dll名,那说明你没有把dll放到合适的位置,一般就和要调用原生函数的类放在一起,当然前提是你成功的生成dll了

2unsatisfiedlinkError:方法名,这个时候你其实dll已经成功生成了,而且位置也正确,它的意思就是你没有定义那个函数,你可能会说,我明明定义了,其实当你发现问题所在,你只能自虐了,肯定是你在C文件中定义函数时有些字母大小写错了,因为其他地方是自动生成的,不会出错。尤其是直接从网上拷贝源程序时经常发生这种问题,有些作者不负责任,把有错误的程序也贴上去。

转自http://www.aichengxu.com/view/33232;

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值