JNI and multiple classloaders

2,639 views
Skip to first unread message

Marcin Orczyk

unread,
Feb 17, 2010, 7:06:27 AM2/17/10
to simple-b...@googlegroups.com
I'm working on a project that has to interface with OpenCL runtime libraries, which means that I need to load shared libraries.
Whenever I start sbt, the first time I access the library (using console or in unit tests) everything works as it should, however the next time I do it, everything crashes with the:
> java.lang.UnsatisfiedLinkError: Native Library /home/zero/tools/jocl/JOCL-0.1.1-beta-src/JOCLJNI/lib/linux/libJOCL-linux-x86_64.so already loaded in another classloader
This kills the whole sbt, so when I start it again, the classloader is fresh and everything works fine
.
Is there a way to force sbt to use the same classloader for everything?
Apparently JVM does not allow the same native library to be referenced from two different classloaders and native libraries are unloaded only when the classloader is garbage collected - which means we have no guarantees about when it happens.
This essentially forces me to restart sbt after each test run or console session. I can live with that, but my productivity would be better if I could avoid JVM startup delay every time I want to run some tests.

I use sbt 0.6.12 and Scala 2.8.0.Beta1 (although, I don't think Scala version has anything to do with this issue).
Anyway, thanks for the great tool!

Marcin

Mark Harrah

unread,
Feb 17, 2010, 1:07:01 PM2/17/10
to simple-b...@googlegroups.com
Hi Marcin,

On Wednesday 17 February 2010 07:06:27 am Marcin Orczyk wrote:
> I'm working on a project that has to interface with OpenCL runtime
> libraries, which means that I need to load shared libraries.
> Whenever I start sbt, the first time I access the library (using console or
> in unit tests) everything works as it should, however the next time I do
> it,
>
> everything crashes with the:
> > java.lang.UnsatisfiedLinkError: Native Library
>
> /home/zero/tools/jocl/JOCL-0.1.1-beta-src/JOCLJNI/lib/linux/libJOCL-linux-x
>86_64.so already loaded in another classloader
> This kills the whole sbt, so when I start it again, the classloader is
> fresh and everything works fine
> .
> Is there a way to force sbt to use the same classloader for everything?
>
> Apparently JVM does not allow the same native library to be referenced from
> two different classloaders and native libraries are unloaded only when the
> classloader is garbage collected - which means we have no guarantees about
> when it happens.
>
> This essentially forces me to restart sbt after each test run or console
> session. I can live with that, but my productivity would be better if I
> could avoid JVM startup delay every time I want to run some tests.

As you imply, you need the native library loaded once per jvm. However, a
native library is associated with the class loader that loadLibrary is called
from, which I assume means that any code that calls that library has to be
loaded from that class loader.

If you are actively developing that code, the only way to reload that code
short of something like JRebel (if it works with code that calls native
libraries) is to drop that class loader and reload it.

If you can put the code that calls the native library in its own project and
develop it separately so that the code never needs to be reloaded, perhaps sbt
could be modified to accept a classpath to load once and make it a parent of
'test', 'run', ... Is this what you meant by "same classloader for
everything"?

'Once' here is a bit loose: you'd actually be restricted to a using single
Scala version and sbt version at a time. That is, no 'reload', '+', '++' or
anything else I'm not thinking of that causes the project definition to be
reloaded.

-Mark

Marc

unread,
Sep 9, 2011, 12:25:15 PM9/9/11
to simple-b...@googlegroups.com
Hello all,

I have recently encountered the same problem here.  I am accessing a jnilib and the first time I run test (using ScalaTest) everything works and the second time, I get this class loader issue.

I have set fork in run := true in my build.sbt

Is there a fix for this or a good way to go about handling this situation.  I admit to not fully understanding the
email above.

m

Marc

unread,
Sep 9, 2011, 12:57:03 PM9/9/11
to simple-b...@googlegroups.com
More research https://groups.google.com/d/msg/simple-build-tool/KBzk3i2sxQc/P8kpZRlcjFUJ
seems to imply that forking is not supported in tests; however, from the xsbt wiki seems to imply otherwise
"To enable forking all run-like methods (runrun-maintest:run, and test:run-main), set fork to true."

How do you go about setting up a separate project to handle this issue?  ~ test is just a really powerful tool.

Please do keep up the great work with sbt.  

Thanks!
m

Mark Harrah

unread,
Sep 11, 2011, 9:37:06 PM9/11/11
to simple-b...@googlegroups.com
On Fri, 9 Sep 2011 09:57:03 -0700 (PDT)
Marc <mill...@gmail.com> wrote:

> More research
> https://groups.google.com/d/msg/simple-build-tool/KBzk3i2sxQc/P8kpZRlcjFUJ
> seems to imply that forking is not supported in tests; however, from the
> xsbt wiki seems to imply otherwise
> https://github.com/harrah/xsbt/wiki/Forking
> "To enable forking all run-like methods (run, run-main, test:run, and
> test:run-main), set fork to true."

Note that this says all run-like tasks, which means sbt can fork applications.

I see that you were a part of this thread:

http://groups.google.com/group/simple-build-tool/browse_thread/thread/57228cc3896d9246/2c4134247fedca60

The native library handling feature mentioned is in 0.11.0-RC0 if you want to see if that works for you.

-Mark

Marc

unread,
Sep 11, 2011, 10:05:02 PM9/11/11
to simple-b...@googlegroups.com
Thank you Mark,

Sorry I am a little confused between everything. How should I go about trying the new feature in 0.11?

I really do appreciate your help, time and work.

Again, thank you.

Mark Harrah

unread,
Sep 11, 2011, 10:32:35 PM9/11/11
to simple-b...@googlegroups.com
On Sun, 11 Sep 2011 19:05:02 -0700 (PDT)
Marc <mill...@gmail.com> wrote:

> Thank you Mark,
>
> Sorry I am a little confused between everything. How should I go about trying the new feature in 0.11?

I don't know if you mentioned the specific error you get, but I assume it is the standard "already loaded in another classloader" message. If so, put your native library either on the classpath or in the java.library.path system property. sbt should then handle multiple uses automatically by making a temporary copy of the library for each use to get around the restriction.

To get the native library on the classpath, you can either put the native library in the lib/ directory, where sbt will pick it up automatically or explicitly specify the absolute path to it:

unmanagedJars in Compile += file("/path/to/nativelib.so")

or for a native library in a sub directory of your project:

unmanagedJars in Compile <+= baseDirectory(base => base/"native"/"nativelib.so")

> I really do appreciate your help, time and work.
>
> Again, thank you.

No problem.

-Mark

Marc

unread,
Sep 11, 2011, 11:43:22 PM9/11/11
to simple-b...@googlegroups.com
Great! I will try this in the AM and report back.

Keep up the great work. If you happen to be at strange loop, please let me buy you a drink :-)

m

Marc

unread,
Sep 12, 2011, 1:00:10 PM9/12/11
to simple-b...@googlegroups.com
Awesome!!!!  This seems to fix everything.  I still had to set the library path, but yeah ~ test works again.

Take care,
m

Jesh

unread,
Sep 30, 2011, 4:23:33 PM9/30/11
to simple-build-tool
Hi,

I'm having trouble getting this to work (using sbt 0.11)

--

val buildSettings = Defaults.defaultSettings ++ Seq (
scalaVersion := "2.9.1",
unmanagedJars in Compile <+= baseDirectory(base => base/"native")
)

-- errors:

build.sbt:1: error: type mismatch;
found : sbt.Project.Initialize[java.io.Serializable]
required: sbt.Project.Initialize[sbt.Task[?]]
Note: java.io.Serializable >: sbt.Task[?], but trait Initialize is
invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
unmanagedJars in Compile <+= baseDirectory(base => base/"native")


Thanks for your help,
Jesh

On Sep 11, 10:32 pm, Mark Harrah <dmhar...@gmail.com> wrote:
> On Sun, 11 Sep 2011 19:05:02 -0700 (PDT)
>
> Marc <millst...@gmail.com> wrote:
> > Thank you Mark,
>
> > Sorry I am a little confused between everything. How should I go about trying the new feature in 0.11?
>
> I don't know if you mentioned the specific error you get, but I assume it is the standard "already loaded in another classloader" message.  If so, put your native library either on the classpath or in thejava.library.pathsystem property.  sbt should then handle multiple uses automatically by making a temporary copy of the library for each use to get around the restriction.

Jason Zaugg

unread,
Oct 1, 2011, 2:45:18 AM10/1/11
to simple-b...@googlegroups.com
On Friday, September 30, 2011 10:23:33 PM UTC+2, Jesh wrote:
Hi,

I'm having trouble getting this to work (using sbt 0.11)

--

val buildSettings = Defaults.defaultSettings ++ Seq (
    scalaVersion := "2.9.1",
    unmanagedJars in Compile <+= baseDirectory(base => base/"native")
)

-- errors:

build.sbt:1: error: type mismatch;
 found   : sbt.Project.Initialize[java.io.Serializable]
 required: sbt.Project.Initialize[sbt.Task[?]]
Note: java.io.Serializable >: sbt.Task[?], but trait Initialize is
invariant in type T.
You may wish to define T as -T instead. (SLS 4.5)
unmanagedJars in Compile <+= baseDirectory(base => base/"native")

Hi Jesh,

`unmanagedJars` is a Task, rather than a Setting, so you must use `map` to initialize rather than `apply`. Furthermore, you want to add the contents of that directory (ie DLLs or .so files), rather than the directory itself.

> inspect unmanaged-jars
[info] Task: scala.collection.Seq[sbt.Attributed[java.io.File]]

> set unmanagedJars in Compile <++= baseDirectory.map(bd => (bd / "native" ***) get) 

I added a page to the Wiki a while ago that explains some common errors like these. [1] (It's not linked to yet as I was hoping for it to be reviewed first).

-jason

Jesh

unread,
Oct 4, 2011, 3:54:23 PM10/4/11
to simple-build-tool
Jason,
Great thanks! That wiki page helps alot.

--Jesh
Reply all
Reply to author
Forward
0 new messages