我使用JNA加载本机库:
MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("mylibrary.so", MyLibrary.class);
现在我想清理并处理库。我已经阅读了dispose
方法,但这是在课程NativeLibrary
上定义的,我应该如何称呼它?
无论如何,是否有必要这样做?我大规模地使用jna和Apache Spark,所以我加载了数千次库,我想知道如果我做的话,有任何资源可以打开{{1 }}?
编辑:我已经看到问题Jna, Unload Dll from java class dynamically,但它没有解决我的问题。没有接受的答案。人们建议拨打dispose
,但NativeLibrary.dispose()
中没有这样的静态方法。如果我尝试转换我的库实例(类型为NativeLibrary
),那么我会得到一个类转换异常。
答案 0 :(得分:3)
您的帖子暗示您主要关注资源消耗。加载它并不需要考虑数千次" - 它很像静态变量,一旦加载就不会重新加载。
如果你想卸载它,你基本上有三个选择。
选项1:
INSTANCE = null;
System.gc(); // or simply wait for the system to do this
无法保证将收集对象,但通过将INSTANCE
设置为null,您可以允许系统回收其资源。 (dispose()
方法作为对象的finalize()
方法的一部分进行调用,因此在最终收集对象时会将其处理掉。)如果您真的完成了实例,这对你来说已经足够了。请注意,如果重新加载库是其他行为所必需的,则不应该依赖此操作,因为无法保证垃圾收集。
选项2:
INSTANCE = null;
NativeLibrary lib = NativeLibrary.getInstance("mylibrary.so");
lib.dispose();
这将显式处理本机库,如果您需要重新加载库以强制重新加载编程行为(而不是重用现有实例),这将是首选方法。请注意,如果在加载库时使用了选项你也需要在这个调用中使用相同的选项。
选项3:使用NativeLibrary.disposeAll()
。这会卸载您的所有库。根据您使用的其他库的数量(再次使用时必须重新加载),这可能对您有用。
请注意,在所有这些选项中,您可能需要在处置后稍微延迟一段时间,以确保本机操作系统也会释放其引用。
答案 1 :(得分:0)
我想添加另一个选项
我想有一个直接在库接口上处理库的方法,所以我们添加一个:
interface MyLibrary extends Library {
// other methods omitted
void dispose()
}
在实例化库时,我会为这个新方法创建一个调用处理程序:
final Map<String, Object> options = new HashMap<>();
options.put(Library.OPTION_INVOCATION_MAPPER, new InvocationMapper() {
@Override
public InvocationHandler getInvocationHandler(NativeLibrary lib, Method m) {
if (m.getName().equals("dispose")) {
return (proxy, method, args) -> {
lib.dispose();
return null;
};
}
return null;
}
});
return Native.load("/path/to/my/lib", MyLibrary.class, options);
然后用法如下:
public void cleanup(MyLibrary lib) {
// other cleanup work
lib.dispose();
}
这就是 MyLibrary
的客户无需了解 JNA 的任何内部结构即可正确处置库的方式。