I benchmarked a code that allocates 1 million java objects with
env->NewObject
env->AllocObject
,env->SetLongField
To my surprise, the code took 250ms and 125ms to execute respectively. This is 10-5x slower than what an equivalent java program would take!
The overhead of the JNI call is also order of magnitude larger than the one mentioned in What makes JNI calls slow? (which goes in the opposite direction java -> Native
).
What makes it so slow? Doesn't C have direct access to Java heap?
Alternatively, is there a more efficient way to pass data from C to java trough JNI?
The java code:
public class Main {
static {
System.loadLibrary("main");
}
private native void bench();
static void bench_java() {
long now = System.currentTimeMillis();
for (int i=0; i < 1000000; i++) new Number(i);
System.out.println(System.currentTimeMillis() - now);
}
public static void main(String[] args) {
new Main().bench();
}
}
public class Number {
long j;
public Number(long j) {
this.j = j;
}
}
The c code:
#include "jni.h"
#include <stdio.h>
#include <sys/time.h>
JNIEXPORT void JNICALL Java_Main_bench(JNIEnv *env, jobject thisObj) {
struct timespec start, end;
jclass cls = (*env)->FindClass(env, "Number");
jmethodID init = (*env)->GetMethodID(env, cls, "<init>", "(J)V");
clock_gettime(CLOCK_MONOTONIC, &start);
for (int i=0; i<1000000; i++) (*env)->NewObject(env, cls, init, 0);
clock_gettime(CLOCK_MONOTONIC, &end);
printf("Time elapsed %lu ms\n", (end.tv_sec - start.tv_sec) * 1000 + (end.tv_nsec - start.tv_nsec) / 1000000);
return;
}