Thursday, October 14, 2010

JNI - A guide to use your native dll in Java

All of you may know what is JNI and why it is used. I was new to Java and JNI when I started working few months back. I'm basically from C++ background and I always had curiosity to learn CLI after learning .Net. But I did not get a chance to do a real world work using CLI. So when I came to java field, I stamped JNI as my next learning area.

Java looked easy to me to code and its flexibility to use open source.  In my current project I use open source libraries a lot. One of my project work was to integrate a C++ application to a Java application. Initially I had designed my java plug-in and native dll following some design pattern like SOA, Factory, Singleton etc. All my integration work is working fine and it showed me good confidence in my work.But, as you know, life is not so simple as you see it! It always come with some hurdle :)

Here comes the juicy part...
Problem is my java application crashes after I exit or press close button. I can not figure out  why it is crashing though I have implemented all JNI methods correctly. I have accessed java object from my C++ dll and updated its fields. Every places I've double checked for reference leak and also destructor for resource deallocation, but everything was just fine.

It was simply saying Javaw.exe crashed. It was saying some problem with the C runtime library.

After getting the above C runtime error, I got to know that java jvm.dll uses msvcr71.dll. My native dll is built upon VS2005 SP1, so it uses msvcr80.dll with sxs assemblies. To know the root cause I debugged the my dll after downloading symbol files of msvcr80.dll from Microsoft site. Call stack simply says it was failed to close some file handle while exiting the process during msvcr80.dll!___crtdll_callstaticterminators()

Then, I added JNI_OnLoad and JNI_OnUnload method to see whether my dll getting unloaded properly by jvm. I found that JNI_OnUnload was not getting called. Which brought me more confusion whether my dll is getting unloaded successfully.

I looked for help in many places over Internet and Java forums. I was not sure what to do next. Somebody in forum asked me use my dll as a separate process. Yes that could solve my problem in failure in dll unloading issue. It is like java does not provide any straight forward API to unload any native dll though its allow you to load it by either Load/Loadlibrary method.

Then I got to know that unless the class loader who has loaded the native library is garbage collected, java will not unload native dlls. Fact is that default class loader loads the native libraries which does not get garbage collected.

So the issue became how to unload a native dll, so that all global variables defined inside my library and its dependent library gets destructed. Finally I found a solution to create my own class loader and load my native class with that loader. When I make my custom class loader null and call gc, then native dll gets unloaded!

So idea is to load your native classes with custom class loader so that you get proper control over your native dll. Implementation wise I had do little modification to make all native methods bundled in an interface and implementing that over native java class.

Implementing custom class loader was a good experience. It is like you load the .Class file in a byte array and ask java to define a class with that byte sequence. So cool... Once you have defined your class you should not redefine by doing the same when you need a second object of the native class. It is better to make class loading part in a static method, the way you load your native dll.

All that cost me huge investigation and time as a beginner. Hope this will help others. Soon I'll post a sample code.