Java : Reuse a native library already loaded?

3.1k Views Asked by At

Disclaimer Not native English speaker, feel free to edit if needed.

I'm having a similar issue that the one explained here : java.lang.UnsatisfiedLinkError: Native Library XXX.so already loaded in another classloader

I'm trying to follow the answer of user2543253. But I really lacks of knowledge in Java and the context is a bit different.

Links

  1. .dll already loaded in another classloader? Seems also related to this question.
  2. https://github.com/PatternConsulting/opencv/issues/7 Similar.
  3. https://cycling74.com/articles/mxj-class-loading Explains the class loader behavior of MXJ

Context

Edit : Not sure if that context is really important, it seems to be the same problem described in link 1.

I want to use OpenCV inside an Application called Max/MSP.

To give an idea, it looks like this :

enter image description here

Max/MSP allows user to assemble Patch by cabling some objects together that are called externals, most of them are coded in C but you can also create externals in Java. To do so you need to instantiate them through an object called "mxj". For example, if my Java class is called TestOpenCV, I will create a box and put "mxj TestOpenCV" inside.

OpenCV seems correctly implemented, for exemple, I can instantiate a Mat object and post its content to Max console.

Problems appears when I change the Java code of the mxj object. To update my object, I delete it and recreate it again. Then, the same issue that explained here appears...

enter image description here

Max console return this error message :

java.lang.UnsatisfiedLinkError: Native Library C:\Windows\System32\opencv_java300.dll already loaded in another classloader at java.lang.ClassLoader.loadLibrary1(Unknown Source) at java.lang.ClassLoader.loadLibrary0(Unknown Source) at java.lang.ClassLoader.loadLibrary(Unknown Source) at java.lang.Runtime.loadLibrary0(Unknown Source) at java.lang.System.loadLibrary(Unknown Source) at OpenCVClassLoad.loadNativeLibrary(OpenCVClassLoad.java:5) at TestOpenCV.(TestOpenCV.java:22) (mxj) unable to alloc instance of TestOpenCV

What I tried

I tried to implement the answer of user2543253. He advices to create a tiny classes that import the native library and export it as a JAR. So I created a new Eclipse project added a source file to it

import org.opencv.core.Core;

public class OpenCVClassLoad {
  public static void loadNativeLibrary() {
    System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
  }
}

I added the openCV JAR to that project and exported it as a JAR.

Then I changed my code according to what user2543253 explained (there is more code,I kept the essential) :

import com.cycling74.max.*;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Scalar;

public class TestOpenCV extends MaxObject {  
  static {
    // System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    OpenCVClassLoad.loadNativeLibrary();
  }

  public TestOpenCV(Atom[] args)
  {
    // ... 
  }

  public void notifyDeleted()
  {
    // ...
  }

  public void bang() {
    // Executed when I trig the little bang button you can see

    Mat m = new Mat(5, 9, CvType.CV_8UC4, new Scalar(0));
    post("OpenCV Mat: " + m);

    Mat mr1 = m.row(1);
    mr1.setTo(new Scalar(1));

    Mat mc5 = m.col(3);
    mc5.setTo(new Scalar(5));

    post("OpenCV Mat data:\n" + m.dump()); 
  }
}

Of course, but that's a bit weird, in order to build correctly that project I kept the JAR from OpenCV in the build path :

enter image description here

As you can see, I also added the tiny class in the project build path. After all of theses modifications, the mxj object stille loads correctly the first time and the bang() method still works but the problem still there. In fact it doesn't change anything from the past situation : If I modify the Java code, delete the object in Max and create a new one, error appears...

Question

There is a lot of SO questions addressing the same type of prob but context is always different and its hard to figure out what to do, especially with my basic knowledge of Java.

A workaround should be to simply reuse that library already loaded, no ? but how to achieve this ? Because if I check the library has already being loaded, I do it using a Try / Catch, if I do nothing else. The externals acts like if the library had never been loaded...

How to reuse that native library ? (Of course, any alternative solution to this is welcome)

1

There are 1 best solutions below

9
On

Just remove the second OpenCVClassLoad.loadNativeLibrary(); in your bang() method. In a plain Java application the code in a static block is only executed once.

Alternatively, you can specify the native library location in Eclipse instead of loading the library through Java source code.