Java loadlibrary分析及如何unload
来源:互联网 发布:铁岭金石网络会所 编辑:程序博客网 时间:2024/06/06 12:47
Java可以通过System.load 和 System.loadLibrary()加载动态库。
但是Java本身并没有提供unload的功能。
下面是在网上看到的一个load的原理及如何unload。地址:http://ppjava.com/?p=1273
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
2
System.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)加载
1
static
{
2
InputStream in =
null
;
3
FileOutputStream out =
null
;
4
try
{
5
String libpath = System.getProperty(
"java.library.path"
);
6
if
(libpath ==
null
|| libpath.length() ==
0
)
7
throw
new
RuntimeException(
"java.library.path is null"
);
8
String path =
null
;
9
String pathSeparator = System.getProperty(
"path.separator"
);
10
StringTokenizer st =
new
StringTokenizer(libpath, pathSeparator);
11
if
(st.hasMoreElements())
12
path = st.nextToken();
13
else
14
throw
new
RuntimeException(
"can not split library path : "
+ libpath);
15
in = Foo.
class
.getResource(
"foo.dll"
).openStream();
16
File fooDll =
new
File(
new
File(path),
"foo.dll"
);
17
out =
new
FileOutputStream(fooDll);
18
byte
[] buffer =
new
byte
[
2048
];
19
int
len;
20
while
((len = in.read(buffer)) != -
1
)
21
out.write(buffer,
0
, len);
22
out.close();
23
fooDll.deleteOnExit();
24
System.loadLibrary(
"foo"
);
25
}
catch
(Throwable e) {
26
e.printStackTrace();
27
}
finally
{
28
// 流的判空和关闭
29
}
30
}
2. 拷贝到temp目录中,用System.load(path)加载
1
static
{
2
InputStream in =
null
;
3
FileOutputStream out =
null
;
4
try
{
5
in = Foo.
class
.getResource(
"/foo.dll"
).openStream();
6
File temporaryDll = File.createTempFile(
"foo"
,
".dll"
);
7
out =
new
FileOutputStream(temporaryDll);
8
byte
[] buffer =
new
byte
[
2048
];
9
int
len;
10
while
((len = in.read(buffer)) != -
1
)
11
out.write(buffer,
0
, len);
12
out.close();
13
temporaryDll.deleteOnExit();
14
System.load(temporaryDll.getPath());
15
}
catch
(Throwable e) {
16
e.printStackTrace();
17
}
finally
{
18
// 流的判空和关闭
19
}
20
}
为什么上面通过getResource取得了URL不直接去加载呢?因为如果把dll和class一起打成jar包,ClassLoader还是不能加载本地库,因为System.load(path)需要的是dll的完整路径,但并不支持jar协议。ClassLoader中用new File(name),当然会找不到文件。
1
URL url = Foo.
class
.getResource(
"/java/lang/String.class"
);
2
System.out.println(url);
3
System.out.println(url.toExternalForm());
4
System.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,让程序退出时卸载动态链接库:
1
Runtime.getRuntime().addShutdownHook(
new
Thread() {
2
public
void
run() {
3
// unloadAllNativeLibs();
4
unloadNativeLibs(temporaryDll.getName());
5
}
6
});
那么如何在程序推出时卸载动态库文件呢?可以通过反射调用私有属性和私有方法来卸载:
1
public
static
synchronized
void
unloadAllNativeLibs() {
2
try
{
3
ClassLoader classLoader = Foo.
class
.getClassLoader();
4
Field field = ClassLoader.
class
.getDeclaredField(
"nativeLibraries"
);
5
field.setAccessible(
true
);
6
Vector<Object> libs = (Vector<Object>) field.get(classLoader);
7
Iterator it = libs.iterator();
8
while
(it.hasNext()) {
9
Object object = it.next();
10
Method finalize = object.getClass().getDeclaredMethod(
"finalize"
);
11
finalize.setAccessible(
true
);
12
finalize.invoke(object);
13
}
14
}
catch
(Throwable th) {
15
th.printStackTrace();
16
}
17
}
18
19
public
static
synchronized
void
unloadNativeLibs(String libName) {
20
try
{
21
ClassLoader classLoader = Foo.
class
.getClassLoader();
22
Field field = ClassLoader.
class
.getDeclaredField(
"nativeLibraries"
);
23
field.setAccessible(
true
);
24
Vector<Object> libs = (Vector<Object>) field.get(classLoader);
25
Iterator it = libs.iterator();
26
while
(it.hasNext()) {
27
Object object = it.next();
28
Field[] fs = object.getClass().getDeclaredFields();
29
for
(
int
k =
0
; k < fs.length; k++) {
30
if
(fs[k].getName().equals(
"name"
)) {
31
fs[k].setAccessible(
true
);
32
String dllPath = fs[k].get(object).toString();
33
if
(dllPath.endsWith(libName)) {
34
Method finalize = object.getClass().getDeclaredMethod(
"finalize"
);
35
finalize.setAccessible(
true
);
36
finalize.invoke(object);
37
}
38
}
39
}
40
}
41
}
catch
(Throwable th) {
42
th.printStackTrace();
43
}
44
}
【注】unloadNativeLibs(String libName)这个 libName 不是那个“foo.dll”,而是一个“foo”+Long类型的随机数+“.dll”。
- Java loadlibrary分析及如何unload
- ubuntu对硬盘的“Load/Unload Cycle威胁”分析及官方解决办法
- UNLOAD
- System.loadLibrary()流程分析
- java System.loadLibrary
- ubuntu对硬盘的“Load/Unload Cycle威胁”分析及官方解决办法,以及网上其它解决方法的评价。
- LoadLibrary
- LoadLibrary
- LoadLibrary
- LoadLibrary
- LoadLibrary
- loadlibrary()
- LoadLibrary
- loadlibrary
- LoadLibrary
- 关于JAVA System.loadLibrary()问题
- Android System.loadLibrary及JNI_OnLoad简介
- Android System.loadLibrary及JNI_OnLoad简介
- 数据结构 队列的基本操作
- 常用的几个第三方 Python 库
- 如何成为一个C++高级程序员
- 数据结构 循环队列的基本操作
- 《C++沉思录》-第九章-- 一个课堂练习的分析(上)
- Java loadlibrary分析及如何unload
- GDB错误:Cannot find bounds of current function
- 数据结构 串(顺序存储)的基本操作
- windows怎么与虚拟机linux共享?
- Graph Databases—Chapter 2 The NOSQL Phenomenon阅读笔记
- Android ProgressBar实现方法列表
- 数据结构 串(链式存储)的基本操作
- MapReduce中第三方jar的存放
- 数据结构 字串的模式匹配 KMP算法