如何处理加载了 JNA 的库

Rap*_*oth 5 jna

我正在使用 JNA 来加载本机库:

MyLibrary INSTANCE = (MyLibrary) Native.loadLibrary("mylibrary.so", MyLibrary.class);
Run Code Online (Sandbox Code Playgroud)

现在我想清理并处置图书馆。我已经读过该dispose方法,但这是在类上定义的NativeLibrary,我应该如何调用它?

无论如何,有必要这样做吗?我正在大规模地将 jna 与 Apache Spark 一起使用,因此我加载了该库数千次,我想知道如果我明确调用 nit ,是否还有任何资源保持打开状态dispose

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

没有公认的答案。人们建议调用NativeLibrary.dispose(),但NativeLibrary. 如果我尝试转换我的库实例(类型为Library),则会收到类转换异常。

Dan*_*dis 5

您的帖子暗示您主要关心资源消耗。这不是加载它“数千次”的问题——它存储在映射中并在可能的情况下重用,就像静态变量一样,一旦加载就不会重新加载。

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

选项1:

INSTANCE = null;
System.gc(); // twice; or wait for the system to do this
Run Code Online (Sandbox Code Playgroud)

无法保证何时(如果有)对象将被收集,但通过设置INSTANCE为 null,您可以允许系统在需要时回收其资源。

在 JNA 5.11.0 及更早版本中,该dispose()方法作为对象方法的一部分进行调用finalize(),因此在最终收集对象时它会被释放。从 JNA 5.12.x 开始,使用 Cleaner 而不是终结器,并且可以更快地卸载它。

如果您确实完成了该实例,这对您来说可能就足够了。请注意,如果其他行为需要重新加载库,则不应依赖此方法,因为无法保证垃圾收集。

选项2:

NativeLibrary lib = NativeLibrary.getInstance("mylibrary.so", <same options as initial loading>);
lib.close(); // For JNA 5.12+. In JNA 5.11 or earlier use lib.dispose();
// Time delay
INSTANCE = Native.load( ... ); // load new instance here
Run Code Online (Sandbox Code Playgroud)

请注意,加载使用getInstance()需要相同的选项,其中包括类加载器

// if loaded like this:
INSTANCE = (LibName) Native.loadLibrary(dllPath, LibName.class);
// then load like this this:
NativeLibrary lib = NativeLibrary.getInstance(dllPath, LibName.class.getClassLoader());
lib.close();
Run Code Online (Sandbox Code Playgroud)

这将显式地处理本机库(从进程内存中卸载它),如果您需要重新加载库以强制重新加载时的编程行为(而不是重用现有实例),这将是首选方法。请注意,如果您使用了选项加载库时,您也需要在此调用中使用相同的选项。请注意,INSTANCE引用初始加载库的变量在此调用后将无效;将其设置为 null 或重新加载库并重新分配它。

选项 3:

NativeLibrary.disposeAll();
Run Code Online (Sandbox Code Playgroud)

这会卸载所有库,本质上是在循环中执行选项 2。根据您使用的其他库的数量(再次使用时必须重新加载),这可能对您有用。

一些注意事项:

  • 在所有这些选项中,您可能需要在处理后有几毫秒的小时间延迟,以确保本机操作系统不会返回相同的句柄。
  • 在 Windows 上,即使库已从进程内存中卸载,JVM 也可能保留对文件本身或其输入/输出流的引用,直到发生 GC,从而阻止您删除文件。 请参阅此问题以进行进一步讨论。