2

I have profiled my Java application and know that it contains a memory leak in native code but not in the application's own Java source code. I'm trying to identify the dependency or dependencies that might be at fault.

Back in earlier versions of the JDK, you could find native libraries in a Java app with something like this:

public class ClassScope {
    private static final java.lang.reflect.Field LIBRARIES;
    static {
        LIBRARIES = ClassLoader.class.getDeclaredField("loadedLibraryNames");
        LIBRARIES.setAccessible(true);
    }
    public static String[] getLoadedLibraries(final ClassLoader loader) {
        final Vector<String> libraries = (Vector<String>) LIBRARIES.get(loader);
        return libraries.toArray(new String[] {});
    }
}

final String[] libraries = ClassScope.getLoadedClasses(ClassLoader.getSystemClassLoader()); 

However, if you try this on JDKs after 9, you get warned that this access will be revoked from Java 12 om:


WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by <class> (file:<file>) to method|constructor
WARNING: Please consider reporting this to the maintainers of <file>
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release

And in JDK 17 the field has been removed completely:

No field loadedLibraryNames in class Ljava/lang/ClassLoader;

So, in a JDK 17 app, what options are there to identify native libraries used via JNI?

  • Wouldn't it be sufficient to search for invocations of `System.loadLibrary` in all your jar files that make up your application? Yes, in theory code could call that reflectively, but I don't know why they'd do that. – Joachim Sauer Feb 23 '23 at 17:43
  • Ok, perhaps but help me understand your suggestion . . . my pom includes dozens of dependencies and those dependencies are jar files that get bundled with the application. . . given that I don't have access to the source code in those jar files, I'm not clear how you propose to check for invocations of `System.loadLibrary` within them. Could you elaborate a bit? Thanks for the suggestion by the way. – Augustin Cayot Feb 23 '23 at 17:48
  • [Something like this](https://stackoverflow.com/questions/930289/how-can-i-find-all-the-methods-that-call-a-given-method-in-java) could quite easily search through all the libraries, but it seems you already got a better option. – Joachim Sauer Feb 23 '23 at 18:56

1 Answers1

2

You can use the -Xlog:library=trace VM flag to print out information about libraries that are loaded and symbol lookups. For instance:

> java '-Xlog:library=info' Main
[0.011s][info][library] Loaded library jsvml.dll, handle 0x00007ffbd4ab0000
[0.052s][info][library] Failed to find _JNI_OnLoad_jimage@8 in library with handle 0x00007ff6a9610000
[0.052s][info][library] Failed to find JNI_OnLoad_jimage in library with handle 0x00007ff6a9610000
[0.053s][info][library] Loaded library C:\Program Files\Java\jdk-17\bin\jimage.dll, handle 0x00007ffbfd960000
[0.053s][info][library] Failed to find _JNI_OnLoad@8 in library with handle 0x00007ffbfd960000
[0.053s][info][library] Failed to find JNI_OnLoad in library with handle 0x00007ffbfd960000
[0.054s][info][library] Found Java_jdk_internal_jimage_NativeImageBuffer_getNativeMap in library with handle 0x00007ffbfd960000
Jorn Vernee
  • 31,735
  • 4
  • 76
  • 93
  • Thanks, never heard of that. What's funny about that JVM option is that when I google it, the only result I can find is your blog post: https://jornvernee.github.io/java/panama-ffi/panama/jni/native/2021/09/13/debugging-unsatisfiedlinkerrors.html – Augustin Cayot Feb 23 '23 at 17:56
  • @AugustinCayot `-Xlog` is a bit of a treasure trove, but it got added in Java 9, so I think the ecosystem is still catching on. Check out `-Xlog:help` too if you're interested. – Jorn Vernee Feb 23 '23 at 19:03