jna

How to dispose library loaded with JNA


I'm using JNA to load a native Library using:

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

Now I want to clean up and dispose the library. I've read about the dispose method but this is defined on the class NativeLibrary, how I am supposed to call this?

Anyway, is it necessary to do that? I'm using jna with Apache Spark on a large scale, so I'm loading the library thousand of times, I'm wondering of there are any resources left open if I do nit excplicitly call dispose?

EDIT: I've seen the question Jna, Unload Dll from java class dynamically, but it does not provide a solution to my problem.

There is no accepted answer. People suggest to call NativeLibrary.dispose(), but there is no such static method in NativeLibrary. If I try to cast my library instance (which is of type Library), then I get a class-cast exception.


Solution

  • Your post implies that you are concerned primarily with resource consumption. This is not a concern for loading it "thousands of times" -- it is stored in a map and reused when possible, so much like a static variable, once loaded it is not reloaded.

    If you do want to unload it, you essentially have three options.

    Option 1:

    INSTANCE = null;
    System.gc(); // twice; or wait for the system to do this
    

    There are no guarantees when (if ever) the object will be collected, but by setting INSTANCE to null, you allow the system to reclaim its resources when it wants to.

    In JNA 5.11.0 and earlier, the dispose() method is called as part of the object's finalize() method, so it gets disposed when the object is eventually collected. As of JNA 5.12.x, a Cleaner is used rather than a finalizer, and may unload this faster.

    If you're really done with the instance, this may be sufficient for you. Note this should not be relied on in cases where reloading the library is necessary for other behavior, as garbage collection is not guaranteed.

    Option 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
    

    Note that loading using getInstance() requires the same options which would include the class loader

    // 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();
    

    This will explicitly dispose of the native library (unloading it from process memory), and would be the preferred method if you need to reload the library to force programmatic behavior on reloading (as opposed to reusing the existing instance.) Note if you used options when loading the library you need to use those same options with this call as well. Note your INSTANCE variable referring to the initial loaded library will be invalid after this call; either set it to null or reload the library and reassign it.

    Option 3:

    NativeLibrary.disposeAll();
    

    This unloads all your libraries, essentially executing Option 2 in a loop. Depending on how many other libraries you use (which will have to be reloaded when used again) this may work for you.

    A few caveats: