-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
java.lang.NoClassDefFoundError running javacpp on Linux #832
Comments
There is most likely some native dependency missing. There is a cause to that exception, maybe it's not showing up for some reason. Alpine is known to be quite buggy though, so it might take a while to figure out the issue, and even when we do, it probably won't be easy to fix. In any case, please try to load the modules manually and see if we can get any better stack traces: Loader.load(avutil.class);
Loader.load(swresample.class);
Loader.load(avcodec.class); |
ok, let me try these commands and see what I can capture. Thank you. EDIT: I'm assuming these are the classes in org.bytedeco.javacpp and NOT the ones in org.bytedeco.javacpp.presets. Is that correct? |
Also @saudet is there a recommended version of Linux to use? It may be more feasible for me to switch. In the meantime I'll try to gather the info you requested. |
Yes, not the ones in the presets package. As mentioned here, the binaries are built with CentOS: |
Tried loading each of these 3 classes in their own try/catch block (so 3 try/catches in total). avutil and swresample loaded without problem. avcodec did not. Unfortunately there was no more information in the exception than what I've posted before. I'm going to try switching to Centos 7 and see if that can work for me. |
@saudet switched over to Centos 7 and am STILL getting the same error. I'm at a loss. What can I do!?!? |
ok, here's what I was able to find: [root@9a3814890b6e javatmp]# ldd org/bytedeco/javacpp/linux-x86_64/libavcodec.so.57 The two missing shared objects are packaged in the jar, however they are not on the system's LD_LIBRARY_PATH. I notice that once I invoke the classes in javacpp a cache directory is created under ~/.javacpp which contains the exploded .so's. If I add that path to my LD_LIBRARY_PATH I see: [root@c0b299fbec4a javatmp]# ldd /root/.javacpp/cache/ffmpeg-3.2.1-1.3-linux-x86_64.jar/org/bytedeco/javacpp/linux-x86_64/libavcodec.so.57 However just getting ldd working is not sufficient to getting my code to work. I think, in part, because I'm changing my LD_LIBRARY_PATH after the JVM starts. And also because that cache directory is created lazily. So now the challenge is: how do I proactively get these .so's into my LD_LIBRARY_PATH during construction of my Docker image? Does it sound like I'm on the right track? Any suggestions? |
Also I noticed this in the properties (this is when running on my Mac where I can step through and debug: platform.cinclude=[<libavutil/avutil.h>, <libavutil/error.h>, <libavutil/mem.h>, <libavutil/mathematics.h>, <libavutil/rational.h>, <libavutil/log.h>, <libavutil/buffer.h>, <libavutil/pixfmt.h>, <libavutil/frame.h>, <libavutil/samplefmt.h>, <libavutil/channel_layout.h>, <libavutil/cpu.h>, <libavutil/dict.h>, <libavutil/opt.h>, <libavutil/pixdesc.h>, <libavutil/imgutils.h>, <libavutil/downmix_info.h>, <libavutil/stereo3d.h>, <libavutil/ffversion.h>, <libavutil/motion_vector.h>, <libavutil/fifo.h>, <libavutil/audio_fifo.h>, log_callback.h, <libswresample/swresample.h>, <libavcodec/avcodec.h>]} However log_callback.h is missing on my Linux system. What is the impact of that missing header file? EDIT: I should add that I copied all of the .so's packaged with the linux-x86_64 jar into my /usr/local/lib directory (so now ldd works) but that still has no resolved the issue. It feels like I just need to get these files into the right location for the library to load them. Any suggestions? |
Also I added an extra log line to try to get the cause of the exception and it is blank
Do I need to set on of the properties in the properties map to get this library to look in the right place for these shared objects (like "/lib64" instead of "/lib" or "/usr/local/lib")? |
None of what you mention is a problem.
Maybe the binaries you have are corrupted. Have you tried to redownload
them?
|
I could try to re-download. But can you explain something to me: It looks like the .so's are loaded as resources from within the jar files (by the class loader) is that right? So then when the classes in the C/C++ layer are initialized where does it search to find the link dependencies? So if libavcodec.so.57 relies on libavutil.so.55 where does it find that dependency? Should it be finding it within the same jar (because that's where it's packaged). Or should it be finding it in ~/.javacpp/cache because that's where the get exploded? Or should it be finding it in $LD_LIBRARY_PATH because that's where libraries get resolved? Or should it be finding it in /lib or /lib64? Ultimately I'm trying (desperately) to understand the JNI path here. Once Class.forName0() native method is invoked I have no insight into what's happening. So understanding that better, from your perspective, would be very helpful. Also, what does it say that Loader.load(avutil.class) and Loader.load(swresample.class) work? Should I understand that to mean that libavutil.so.55 and libjniavutil.so as well as libswresample.so and libjniswresample.so are resolving their linker dependencies ok? And that, for some reason, libavcodec.so and libjniavcodec.so are not resolving those dependencies? Lastly, is there any way to get insight into what exactly is failing inside the native code? Looks like the ClassNotFoundException that is being thrown there is turned into a string which simply says "Could not initialize class org.bytedeco.javacpp.avcodec". Can I get more info? Are there logs somewhere that I should consult? Are there logging properties I should set? Are there system properties I should enable? Again, any clues would be greatly appreciated. In the meantime I will try re-downloading the jars. |
Also how concerned should I be about these missing dependencies: [root@7c2cca9eebf8 lib]# ldd libjniavdevice.so |
Like I said, the JDK will tell us what is the cause of the error. The fact
that you don't get anything points to a problem with your version of Java
or Linux. I can't do anything about that!
To understand more about all this, please go and learn more about shared
objects on the Linux platform.
|
@saudet I'm trying to understand how YOUR library is working. I have a working understanding of shared objects on Linux. But I'm asking you to explain how you expect things to work. I honestly don't know how to get the JDK to tell me anything more than I've provided for you. Can you please tell me how to do that? What more do you expect to see? Why, when I try to get the Cause of the exception is it null/empty? What are you expecting the exception from the native code to tell you? Can you please cut/paste examples of other NoClassDefFoundErrors loading avcodec that you've seen? That might at least give me a place to start looking. Look, I know this is painful and that I'm taxing you with all these questions. But can you see how frustrating this is from my perspective. The person who, presumably, knows that most about this code and this setup is not being terribly responsive. I want to collaborate with you. I want to provide you with whatever information I can to help us debug this together. Pointing me back at the internet to learn about shared objects is not productive. How can we move forward here? |
Here's the kind of stack trace you're supposed to get:
https://github.com/bytedeco/javacpp-presets/wiki/Debugging-UnsatisfiedLinkError-on-Windows
You can try to set LD_LIBRARY_PATH before launching the JDK, but that won't
help, because that's not where the problem is: avutil loads fine for
example.
If you want to figure out what the problem is, first figure out why you're
not getting this info from the JDK! Fiddling with .so files probably won't
help.
|
Thank you @saudet. Can you please explain, though, why I'm seeing a NoClassDefFoundError rather than an UnSatisfiedLinkeError? And how are those things different? It seems like the latter is thrown because a shared object simply isn't in the path. I think in this case all the shared objects are there, but the invocation of the avcodec native class is blowing up for some reason. |
Maybe we're not getting an UnsatisfiedLinkError as the cause, maybe that's the point. That's what I'm saying we need to know. You could try to consult upstream with the authors of the JDK! |
One thing that might help is setting the
"org.bytedeco.javacpp.logger.debug" system property to "true". That will
print out what the Loader is doing...
|
In the example you listed here's the stack: java.lang.UnsatisfiedLinkError: no jniFlyCapture2 in java.library.path So are you surmising that my stack should be: ? So what, I believe, is happening, is that we are newing a class in libavcode.so (via libjniavcodec.so) and that class is referencing other things that are not present OR it's blowing up due to memory or something else. In any case let me try setting the system property that you just mentioned. Also if you have any thoughts on the afore mentioned unsatisfied dependencies that I mentioned that would be helpful as well. Again, thank you. |
With debug logging: My code after this!
|
It's failing on a very simple call to get a reference to the Loader in
native code:
https://github.com/bytedeco/javacpp/blob/master/src/main/java/org/bytedeco/javacpp/tools/Generator.java#L687
Have you tried to change the version of your JDK? If you're stuck with a
specific vendor and/or version, then please contact the vendor of your JDK.
This doesn't look like a problem with JavaCPP, Linux, or FFmpeg.
|
Is there a recommended version of the JDK? I can try updating. Just so I understand then. The root problem is this: Error loading class org/bytedeco/javacpp/Loader. And that is, in turn, leading to a failure to load avcodec.class? But not leading to a failure to load avutil.class or swresample.class. Is that correct? Put another way: Why does the Loader class only fail to load AFTER jniavcodec is extracted and loaded? 02:16:06 |
@saudet btw, thank you for the code link. What does this mean: jclass cls = env->FindClass(JavaCPP_classNames[i]);"); that is, under what conditions would "cls" be null or env->ExceptionCheck() be true? Could there be some underlying system constraint issue? |
Possibly, never heard of anyone with that issue though.
|
Ok, I got it that you've not seen this problem before. However, not having seen it before is not a solution and, unfortunately, I need a solution. So, under what condition would env->FindClass return null? |
Ok, thanks @saudet I'll take a look at that. In the meantime can you answer this question for me: I see that avutil, avcodec, and swresample get reloaded every time one of the jars is extracted and loaded. I'm assuming each of those involves an invocation of the Loader class. Is that correct? If so, can you speculate as to what is special about the case where libjniavcodec is extracted and loaded? What I'm getting at is: Is there still potentially a problem with libavcodec and/or one of its dependencies? And could that problem be the cause of the failure to load the Loader class? Or are the two things coincidences? |
Might be related to this: #791
|
This seems promising. I will try it first thing tomorrow morning. Thank you. |
Tried increasing the stack size to 1mb and that still didn't work. Also set the number of shadow pages to 20 and that didn't help either. ::sigh:: |
May not be terribly helpful, but could you tell us what Java runtime you are currently using for completeness sake? (I think |
From the docker file: ENV JDK_URL http://download.oracle.com/otn-pub/java/jdk/8u91-b14/jdk-8u91-linux-x64.rpm Does that help? |
I use OpenJDK 8, whatever version works fine. Oracle JDK 8 also works fine,
obviously.
Docker containers come with weird bugs and limits. I'd check that first.
|
I'm attempting to get a setup running outside of Docker. Again, to reiterate, this works just fine on my local Mac OS X. I don't think it's a Docker issue. I really think that there is a missing "Caused By" here and that Caused By will probably tell me that the .so's that I have are not internally consistent. That's the only thing I can think of. Like I said, I tried increasing the stack space and the shadow page space. But to me this feels like the init of the avcodec class is invoking something in libavcodec that is not finding what it needs elsewhere (even though ldd says that all the dependencies are satisfied). Also, in one of my earlier notes I included that the following dependencies were missing: libXfixes.so.3 => not found Not sure how important those are. That came from checking "ldd libjniavdevice.so" which seems like it gets loaded AFTER avcodec. So not sure how relevant that is (yet?). |
This change might help: bytedeco/javacpp@7968093 |
Great, how could I test that out? |
Use the 1.3.4-SNAPSHOT artifacts: http://bytedeco.org/builds/
|
Ok, I haven't tried the snaphshot yet. But I DO HAVE IT WORKING on a Centos 7 Docker image! I had previously got it working on a Centos 7 VM using Vagrant. I noticed that my max heap was set to 1Gb. That resulted in a bunch of OOM errors that did not make it to my logs in AWS but were on the console. So I increased my Docker memory requirement and max heap both to 3Gb. I also followed the advice of one of the other issues mentioned earlier and bumped up my stack size (-Xss2m) as well as set the shadow page size to 20. With these settings I now get the output that I expect! I do see some debug messages from javacpp saying that libXfixes.so is missing. But that doesn't seem to affect my output. In any case this is great and gives me a path forward. At some point in the future I'll try returning to Alpine Linux with the afore mentioned settings and see if that works as well. Thanks for your help on this. |
1 GB is pretty small, so you were just running out of memory it seems. In any case, great to hear it's working well now! |
Duplicate of bytedeco/javacpp-presets#1379 |
Sorry for the multiple posts but I'm really trying to get some help resolving this issue. I'm trying to use the FFmpegFrameGrabber class on an Alpine Linux system in order to do some frame grabs from videos (hls and mp4 format). I continue to run into the following error:
Error loading class org/bytedeco/javacpp/Loader.
java.lang.NoClassDefFoundError: Could not initialize class org.bytedeco.javacpp.avcodec
at java.lang.Class.forName0(Native Method) ~[?:1.8.0_131]
at java.lang.Class.forName(Class.java:348) ~[?:1.8.0_131]
at org.bytedeco.javacpp.Loader.load(Loader.java:739) ~[javacpp-1.3.3.jar:1.3.3]
at org.bytedeco.javacpp.Loader.load(Loader.java:684) ~[javacpp-1.3.3.jar:1.3.3]
at org.bytedeco.javacpp.avformat$AVFormatContext.(avformat.java:2819) ~[ffmpeg-3.2.1-1.3.jar:1.3.3]
at org.bytedeco.javacv.FFmpegFrameGrabber.startUnsafe(FFmpegFrameGrabber.java:509) ~[javacv-1.3.3.jar:1.3.3]
at org.bytedeco.javacv.FFmpegFrameGrabber.start(FFmpegFrameGrabber.java:503) ~[javacv-1.3.3.jar:1.3.3]
Here's my linux version: Linux version 4.9.27-14.31.amzn1.x86_64 (mockbuild@gobi-build-60006) (gcc version 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC) ) #1 SMP Wed May 10 01:58:40 UTC 2017
Here's my gradle dependencies:
This Linux box is running inside of a Docker image. I've tried building ffmpeg directly as part of the construction of the docker image (as seen here: https://hub.docker.com/r/opencoconut/ffmpeg/~/dockerfile/). That did not work.
I tried opening up all the linux-x86_64 jars and copying all the .so's to my /lib directory. That did not work.
I'm a n00b at ffmpeg. I have my code working just fine on my Mac laptop that I use for development. I was hoping the linux box would similarly "just work". Please if anyone @saudet or anyone else has any clues I really need to get this figured out. Any additional info that I can provide please just let me know. Or any additional debug steps I can take just let me know. Thank you.
EDIT: Here's my ffmepg setup on the box itself. I just realized that this may be old:
fmpeg version 3.2.1 Copyright (c) 2000-2016 the FFmpeg developers
built with gcc 6.3.0 (Alpine 6.3.0)
configuration: --enable-version3 --enable-gpl --enable-nonfree --enable-small --enable-libmp3lame --enable-libx264 --enable-libx265 --enable-libvpx --enable-libtheora --enable-libvorbis --enable-libopus --enable-libass --enable-libwebp --enable-postproc --enable-avresample --enable-libfreetype --enable-openssl --disable-debug
libavutil 55. 34.100 / 55. 34.100
libavcodec 57. 64.101 / 57. 64.101
libavformat 57. 56.100 / 57. 56.100
libavdevice 57. 1.100 / 57. 1.100
libavfilter 6. 65.100 / 6. 65.100
libavresample 3. 1. 0 / 3. 1. 0
libswscale 4. 2.100 / 4. 2.100
libswresample 2. 3.100 / 2. 3.100
libpostproc 54. 1.100 / 54. 1.100
EDIT 2: fwiw I updated ffmpeg on the box. Still no luck
ffmpeg version 3.4 Copyright (c) 2000-2017 the FFmpeg developers
built with gcc 6.3.0 (Alpine 6.3.0)
configuration: --enable-version3 --enable-gpl --enable-nonfree --enable-small --enable-libmp3lame --enable-libx264 --enable-libx265 --enable-libvpx --enable-libtheora --enable-libvorbis --enable-libopus --enable-libass --enable-libwebp --enable-postproc --enable-avresample --enable-libfreetype --enable-openssl --disable-debug
libavutil 55. 78.100 / 55. 78.100
libavcodec 57.107.100 / 57.107.100
libavformat 57. 83.100 / 57. 83.100
libavdevice 57. 10.100 / 57. 10.100
libavfilter 6.107.100 / 6.107.100
libavresample 3. 7. 0 / 3. 7. 0
libswscale 4. 8.100 / 4. 8.100
libswresample 2. 9.100 / 2. 9.100
libpostproc 54. 7.100 / 54. 7.100
The text was updated successfully, but these errors were encountered: