Intro
Although I did some stuff with JNI in Java during my time in schooling, I never wrote it about it here. Nor gave examples.
JNI
Java Native Interface is used basically for C/C++ interfaces, in my example, I was doing the processing of some data in Java but the data was generated (compiled, traced, generated) in C/C++ (where I would collect the data as well). (Btw, it is just me or this new way to write in wordpress with blocks sucks, like really)
That being said, the quickest example with JNI is by doing in a JAVA class
public class JNIExample{ //
static {
System.loadLibrary("hello");
}
private native void sayHello();
public static void main(String[] args) {
new HelloJNI().sayHello();
}
}
After creating the file, we compile it:
fdemeloj@fdemeloj jni]$ javac JNIExample.java
Then create the header with javah, and not javac -h as used to be back in Poly times. Write a HelloWorld.c:
#include <jni.h> //import jni header
#include <stdio.h> //Import the stdio
#include "HelloWorld.h" //Insert the header
JNIEXPORT void JNICALL
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("Hello World!\n");
return;
}
Write a Make file to make the compilation process easy for our Shared library
all:
@echo "Generating Shared Library"
cc -I. -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -fPIC -shared -o libHelloWorld.so HelloWorld.c HelloWorld.h
clean:
@echo "Cleaning the generated SH files"
rm *.so
To run the code, just run java (no need for LD_LIBRARY_PATH if you are using -Djava.library.path=.)
export LD_LIBRARY_PATH=.
[fdemeloj@fdemeloj jni]$ java HelloWorld
Hello World!
The cool thing is, IT is a shared library totally independent from the JAVA implementation (tcharam, that’s JNI), so then if we want to change the library to this:
Java_HelloWorld_print(JNIEnv *env, jobject obj)
{
printf("After change!\n");
return;
}
Just recompile the shared library with Make clean;Make. and It’s all good:
[fdemeloj@fdemeloj jni]$ java HelloWorld
After change!
Next thing is to test the GC collections with JNI, from this link. From the same process, we run Makefile, that takes the java and compile it.
#include <jni.h>
#include <CriticalGC.h>
static jbyte* sink;
JNIEXPORT void JNICALL Java_CriticalGC_acquire(JNIEnv* env, jclass klass, jintArray arr) {
sink = (*env)->GetPrimitiveArrayCritical(env, arr, 0);
}
JNIEXPORT void JNICALL Java_CriticalGC_release(JNIEnv* env, jclass klass, jintArray arr) {
(*env)->ReleasePrimitiveArrayCritical(env, arr, sink, 0);
}
Running it with Shenandoah we see the difference and how it is so fast:
[fdemeloj@fdemeloj critical-gc]$ make run-shenandoah
time java -Djava.library.path=. -Xms4g -Xmx4g -verbose:gc -XX:+UseShenandoahGC CriticalGC
Acquired
Releasing
Acquired
Releasing
Acquired
Releasing
Acquired
Releasing
Acquired
[Pause Init Mark, 0.533 ms]
[Concurrent marking 2880M->2988M(4096M), 216.052 ms]
[Pause Final Mark 2988M->920M(4096M), 2.220 ms]
[Concurrent reset bitmaps 922M->926M(4096M), 0.946 ms]
Releasing
Acquired
Releasing
Acquired
^CCancelling concurrent GC: Stopping VM
Releasing
Acquired
I mean, comparing with the other GC’s approaches this Shenandoah doesn’t even stop.
REFERENCE:
Following this reference