热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

java动态库卸载_java加载、卸载动态链接库文件

Java加载JNI的动态库,有两种方式:publicstaticvoidload(Stringfilename),从作为动态库的本地文件系

Java加载JNI的动态库,有两种方式:

public static void load(String filename),从作为动态库的本地文件系统中以指定的文件名加载代码文件。文件名参数必须是完整的路径名。调用 System.load(name) 实际上等效于调用:Runtime.getRuntime().load(name)。

public static void loadLibrary(String libname),加载由 libname 参数指定的系统库。将库名映射到实际系统库的方法取决于系统。调用 System.loadLibrary(name) 实际上等效于调用:Runtime.getRuntime().loadLibrary(name)。

jni加载classpath中的动态链接库

1// 系统自己会判断扩展名是dll还是so

2System.loadLibrary("test");

jni加载jar包中的动态链接库

部署应用的时候要加载jar包中的动态链接库文件,可以将本地库拷贝到环境变量path指定的路径中。一般在windows平台上直接copy到

“C:\WINDOWS\System32”目录下了事,但这样需要用户做额外操作,有时候当前系统用户也没有权限拷贝库文件到指定目录。

有人可能会想到,在Java代码中利用System.setProPerty设置lib path,指向动态库文件所在路径。不过此法不可行,因为一旦Java虚拟机启动以后,lib path就是只读的,就不能再设置进去值了。

这个问题可以这样解决:

把dll放在classpath中,用Class.getResource(str).openStream()读取这个dll,

拷贝到classpath中,用System.loadLibrary(name)加载;

如果没有权限拷贝到指定目录,也可以拷贝到temp目录中,用System.load(path)加载。

1. 拷贝到classpath中,用System.loadLibrary(name)加载

1static {

2InputStream in =null;

3FileOutputStream out =null;

4try {

5String libpath = System.getProperty("java.library.path");

6if (libpath ==null || libpath.length() ==0)

7throw new RuntimeException("java.library.path is null");

8String path =null;

9String pathSeparator = System.getProperty("path.separator");

10StringTokenizer st =new StringTokenizer(libpath, pathSeparator);

11if (st.hasMoreElements())

12path = st.nextToken();

13else

14throw new RuntimeException("can not split library path : " + libpath);

15in = Foo.class.getResource("foo.dll").openStream();

16File fooDll =new File(new File(path),"foo.dll");

17out =new FileOutputStream(fooDll);

18byte[] buffer =new byte[2048];

19int len;

20while ((len = in.read(buffer)) != -1)

21out.write(buffer,0, len);

22out.close();

23fooDll.deleteOnExit();

24System.loadLibrary("foo");

25}catch (Throwable e) {

26e.printStackTrace();

27}finally {

28// 流的判空和关闭

29}

30}

2. 拷贝到temp目录中,用System.load(path)加载

1static {

2InputStream in =null;

3FileOutputStream out =null;

4try {

5in = Foo.class.getResource("/foo.dll").openStream();

6File temporaryDll = File.createTempFile("foo",".dll");

7out =new FileOutputStream(temporaryDll);

8byte[] buffer =new byte[2048];

9int len;

10while ((len = in.read(buffer)) != -1)

11out.write(buffer,0, len);

12out.close();

13temporaryDll.deleteOnExit();

14System.load(temporaryDll.getPath());

15}catch (Throwable e) {

16e.printStackTrace();

17}finally {

18// 流的判空和关闭

19}

20}

为什么上面通过getResource取得了URL不直接去加载呢?因为如果把dll和class一起打成jar包,ClassLoader还是不能加载本地库,因为System.load(path)需要的是dll的完整路径,但并不支持jar协议。ClassLoader中用new File(name),当然会找不到文件。

1URL url = Foo.class.getResource("/java/lang/String.class");

2System.out.println(url);

3System.out.println(url.toExternalForm());

4System.out.println(url.getFile());

以上代码输出结果如下:

jar:file:/E:/Java/jdk1.6.0_31/jre/lib/rt.jar!/java/lang/String.class

jar:file:/E:/Java/jdk1.6.0_31/jre/lib/rt.jar!/java/lang/String.class

file:/E:/Java/jdk1.6.0_31/jre/lib/rt.jar!/java/lang/String.class

jni卸载动态库文件

事实证明以上调用deleteOnExit()方法并不能在系统退出后删除动态库文件,由于程序占用而导致无法删除,所以要在程序退出时卸载动态库文件,这个样在程序退出时就可以删除动态临时创建的动态库文件了。我们在程序中加个hook,让程序退出时卸载动态链接库:

1Runtime.getRuntime().addShutdownHook(new Thread() {

2public void run() {

3// unloadAllNativeLibs();

4unloadNativeLibs(temporaryDll.getName());

5}

6});

那么如何在程序推出时卸载动态库文件呢?可以通过反射调用私有属性和私有方法来卸载:

1public static synchronized void unloadAllNativeLibs() {

2try {

3ClassLoader classLoader = Foo.class.getClassLoader();

4Field field = ClassLoader.class.getDeclaredField("nativeLibraries");

5field.setAccessible(true);

6Vector libs = (Vector) field.get(classLoader);

7Iterator it = libs.iterator();

8while (it.hasNext()) {

9Object object = it.next();

10Method finalize = object.getClass().getDeclaredMethod("finalize");

11finalize.setAccessible(true);

12finalize.invoke(object);

13}

14}catch (Throwable th) {

15th.printStackTrace();

16}

17}

18

19public static synchronized void unloadNativeLibs(String libName) {

20try {

21ClassLoader classLoader = Foo.class.getClassLoader();

22Field field = ClassLoader.class.getDeclaredField("nativeLibraries");

23field.setAccessible(true);

24Vector libs = (Vector) field.get(classLoader);

25Iterator it = libs.iterator();

26while (it.hasNext()) {

27Object object = it.next();

28Field[] fs = object.getClass().getDeclaredFields();

29for (int k =0; k

30if (fs[k].getName().equals("name")) {

31fs[k].setAccessible(true);

32String dllPath = fs[k].get(object).toString();

33if (dllPath.endsWith(libName)) {

34Method finalize = object.getClass().getDeclaredMethod("finalize");

35finalize.setAccessible(true);

36finalize.invoke(object);

37}

38}

39}

40}

41}catch (Throwable th) {

42th.printStackTrace();

43}

44}

【注】unloadNativeLibs(String libName)这个 libName 不是那个“foo.dll”,而是一个“foo”+Long类型的随机数+“.dll”。



推荐阅读
  • 使用Maven JAR插件将单个或多个文件及其依赖项合并为一个可引用的JAR包
    本文介绍了如何利用Maven中的maven-assembly-plugin插件将单个或多个Java文件及其依赖项打包成一个可引用的JAR文件。首先,需要创建一个新的Maven项目,并将待打包的Java文件复制到该项目中。通过配置maven-assembly-plugin,可以实现将所有文件及其依赖项合并为一个独立的JAR包,方便在其他项目中引用和使用。此外,该方法还支持自定义装配描述符,以满足不同场景下的需求。 ... [详细]
  • Netty框架中运用Protobuf实现高效通信协议
    在Netty框架中,通过引入Protobuf来实现高效的通信协议。为了使用Protobuf,需要先准备好环境,包括下载并安装Protobuf的代码生成器`protoc`以及相应的源码包。具体资源可从官方下载页面获取,确保版本兼容性以充分发挥其性能优势。此外,配置好开发环境后,可以通过定义`.proto`文件来自动生成Java类,从而简化数据序列化和反序列化的操作,提高通信效率。 ... [详细]
  • 深入解析Android 4.4中的Fence机制及其应用
    在Android 4.4中,Fence机制是处理缓冲区交换和同步问题的关键技术。该机制广泛应用于生产者-消费者模式中,确保了不同组件之间高效、安全的数据传输。通过深入解析Fence机制的工作原理和应用场景,本文探讨了其在系统性能优化和资源管理中的重要作用。 ... [详细]
  • 在Android平台中,播放音频的采样率通常固定为44.1kHz,而录音的采样率则固定为8kHz。为了确保音频设备的正常工作,底层驱动必须预先设定这些固定的采样率。当上层应用提供的采样率与这些预设值不匹配时,需要通过重采样(resample)技术来调整采样率,以保证音频数据的正确处理和传输。本文将详细探讨FFMpeg在音频处理中的基础理论及重采样技术的应用。 ... [详细]
  • Java能否直接通过HTTP将字节流绕过HEAP写入SD卡? ... [详细]
  • 在Android应用开发中,实现与MySQL数据库的连接是一项重要的技术任务。本文详细介绍了Android连接MySQL数据库的操作流程和技术要点。首先,Android平台提供了SQLiteOpenHelper类作为数据库辅助工具,用于创建或打开数据库。开发者可以通过继承并扩展该类,实现对数据库的初始化和版本管理。此外,文章还探讨了使用第三方库如Retrofit或Volley进行网络请求,以及如何通过JSON格式交换数据,确保与MySQL服务器的高效通信。 ... [详细]
  • 在探讨Hibernate框架的高级特性时,缓存机制和懒加载策略是提升数据操作效率的关键要素。缓存策略能够显著减少数据库访问次数,从而提高应用性能,特别是在处理频繁访问的数据时。Hibernate提供了多层次的缓存支持,包括一级缓存和二级缓存,以满足不同场景下的需求。懒加载策略则通过按需加载关联对象,进一步优化了资源利用和响应时间。本文将深入分析这些机制的实现原理及其最佳实践。 ... [详细]
  • Android中将独立SO库封装进JAR包并实现SO库的加载与调用
    在Android开发中,将独立的SO库封装进JAR包并实现其加载与调用是一个常见的需求。本文详细介绍了如何将SO库嵌入到JAR包中,并确保在外部应用调用该JAR包时能够正确加载和使用这些SO库。通过这种方式,开发者可以更方便地管理和分发包含原生代码的库文件,提高开发效率和代码复用性。文章还探讨了常见的问题及其解决方案,帮助开发者避免在实际应用中遇到的坑。 ... [详细]
  • 本文介绍了如何利用Struts1框架构建一个简易的四则运算计算器。通过采用DispatchAction来处理不同类型的计算请求,并使用动态Form来优化开发流程,确保代码的简洁性和可维护性。同时,系统提供了用户友好的错误提示,以增强用户体验。 ... [详细]
  • 在ElasticStack日志监控系统中,Logstash编码插件自5.0版本起进行了重大改进。插件被独立拆分为gem包,每个插件可以单独进行更新和维护,无需依赖Logstash的整体升级。这不仅提高了系统的灵活性和可维护性,还简化了插件的管理和部署过程。本文将详细介绍这些编码插件的功能、配置方法,并通过实际生产环境中的应用案例,展示其在日志处理和监控中的高效性和可靠性。 ... [详细]
  • 本文深入解析了 jQuery 中用于扩展功能的三个关键方法:`$.extend()`、`$.fn` 和 `$.fn.extend()`。其中,`$.extend()` 用于扩展 jQuery 对象本身,而 `$.fn.extend()` 则用于扩展 jQuery 的原型对象,使自定义方法能够作为 jQuery 实例的方法使用。通过这些方法,开发者可以轻松地创建和集成自定义插件,增强 jQuery 的功能。文章详细介绍了每个方法的用法、参数及实际应用场景,帮助读者更好地理解和运用这些强大的工具。 ... [详细]
  • 在本地环境中部署了两个不同版本的 Flink 集群,分别为 1.9.1 和 1.9.2。近期在尝试启动 1.9.1 版本的 Flink 任务时,遇到了 TaskExecutor 启动失败的问题。尽管 TaskManager 日志显示正常,但任务仍无法成功启动。经过详细分析,发现该问题是由 Kafka 版本不兼容引起的。通过调整 Kafka 客户端配置并升级相关依赖,最终成功解决了这一故障。 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 本文详细探讨了Zebra路由软件中的线程机制及其实际应用。通过对Zebra线程模型的深入分析,揭示了其在高效处理网络路由任务中的关键作用。文章还介绍了线程同步与通信机制,以及如何通过优化线程管理提升系统性能。此外,结合具体应用场景,展示了Zebra线程机制在复杂网络环境下的优势和灵活性。 ... [详细]
author-avatar
mobiledu2502887833
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有