如何处理用 JNA 加载的库

How to dispose library loaded with JNA

我正在使用 JNA 加载本机库,方法是:

MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("mylibrary.so", MyLibrary.class);

现在我想清理和处理库。我读过 dispose 方法,但这是在 class NativeLibrary 上定义的,我应该怎么称呼它?

无论如何,有必要这样做吗?我正在大规模使用 jna 和 Apache Spark,所以我加载了数千次库,我想知道如果我明确地调用 dispose?[=18,是否还有任何资源处于打开状态=]

编辑:我已经看到问题 Jna, Unload Dll from java class dynamically,但它没有为我的问题提供解决方案。

没有可接受的答案。人们建议调用NativeLibrary.dispose(),但是在NativeLibrary中没有这个静态方法。如果我尝试转换我的库实例(类型为 Library),那么我会得到一个 class-cast 异常。

您的 post 意味着您主要关注资源消耗。这不是加载它的问题 "thousands of times" -- 它很像一个静态变量,一旦加载就不会重新加载。

如果您确实要卸载它,基本上有三个选择。

选项 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();

这将卸载您的所有库。根据您使用的其他库的数量(再次使用时必须重新加载),这可能对您有用。

请注意,在所有这些选项中,您可能需要 a small time delay 配置后的几毫秒,以确保本机 OS 不会 return 相同的句柄。

我想添加另一个选项,

  • 不依赖垃圾收集器
  • 仅使用 public API
  • 具有最好的可供性

我想有一个直接在库界面上配置库的方法,所以让我们添加一个:

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 的任何内部结构即可正确处理库的方式。