1

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)

snoob dogg
  • 2,491
  • 3
  • 31
  • 54

1 Answers1

0

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.

howlger
  • 31,050
  • 11
  • 59
  • 99
  • Unfortunalty, your first solution will not work, I already tried, the explanation is probably here : https://cycling74.com/articles/mxj-class-loading. When I change the JAVA code, it is recompilated. Hence, it has a more recent class file, MXJ detect it and create a new class loader.. I will read your alternative solution, I didn't found that one yet. I edited the post to add that link and removed the second OpenCVClassLoad.loadNativeLibrary(); which is useless. – snoob dogg Sep 16 '17 at 10:07
  • So I tried the alternative solution, but it doesn't seems to help. In fact I don't see how it should help, the problem comes from the class loader. Do you mean that by setting the native library location, I don't need anymore to use System.loadLibrary(); or class loader ? – snoob dogg Sep 16 '17 at 11:47
  • Yes, either set the native library location (= `-Djava.library.path=...`) or load the library at runtime via `System.loadLibrary()`. In the second case, you could add `new Exception().printStackTrace();` to your code to find out from where and how often your code is executed. – howlger Sep 16 '17 at 21:24
  • I tried to set Native Library Location everywhere I can :D nothing worked, it acts like if the dll wasn't found which is probably the case... java.lang.UnsatisfiedLinkError: org.opencv.core.Mat.n_Mat(IIIDDDD)J Doing this, I don't use System.loadLibrary(), are you I don't need to do anything else ? The linked article in comment above state that each time the class file is modified, Max/MSP will use a new classLoader but the Native lib loaded previously will stay in memory. Not 100% sure , but that's how I see it for the moment... – snoob dogg Sep 16 '17 at 23:19
  • Could you try it without `System.loadLibrary()` and with [putting your DLL in the _support_ directory](https://docs.cycling74.com/max7/vignettes/packages)? – howlger Sep 17 '17 at 07:42
  • I placed the DLL inside the Max/MSP directory C:/Program Files/Cycling '74/Max 7/resources/support. And set up Native Location like that : https://i.snag.gy/iJOxjA.jpg . It doesn't worked, same error as described before. but . Maybe should I create a package ? I've never done anything like that. – snoob dogg Sep 17 '17 at 11:40
  • I also discovered an mxj project on Github that seems to use a Native Library without using System.loadLibrary : https://github.com/timini/maxSerial . but, unfortunatly it has been done for Max/MSP 5, folders structure has deeply changed since that version... – snoob dogg Sep 17 '17 at 11:45
  • If you start your application as a _Max 7_ application which has its own class loader, then don't use either `System.loadLibrary()` nor native library location / `-Djava.library.path=...`. Instead, use the _Max 7_ mechanism which seems to be [putting the DLL into the `support` folder](https://docs.cycling74.com/max7/vignettes/packages) (see also [here](https://docs.cycling74.com/max7/vignettes/standalone_platform_win)). If it does not work, the `UnsatisfiedLinkError` tells you, whether the DLL was not found or loaded twice (_"already loaded in another classloader"_). – howlger Sep 17 '17 at 21:03
  • I commented the `System.loadLibrary()` line, removed path in Native Library Location, restarded Max and the OpenCV DLL is in main support folder. I'm still getting : `java.lang.UnsatisfiedLinkError: org.opencv.core.Mat.n_Mat(IIIDDDD)J` this is the error I get when the DLL is not found. Be aware that I'm not creating a Max 7 Application nor a package but simply a patch where I'm using the mxj object. – snoob dogg Sep 18 '17 at 12:04