Java JNI调用比预期慢(至少2毫秒/调用)

bgr*_*nks 7 c java performance java-native-interface

我从其他几个报告中读到,人们通常会在一个简单的基本JNI呼叫上大约4-80 ns:

什么使JNI呼叫变慢?

对于琐碎的原生方法,去年我发现在我的Windows桌面上平均调用40 ns,在我的Mac桌面上调用11 ns.

使用JNI可能增加的性能?

然而,JNI通常需要大约30 ns.

当我在我的JNI代码中调用简单方法时(简单来说,我的意思是时间int返回类型int只有一个参数),我的往返调用时间(用System.nanoTIme测量)在50,000-80,000 ns之间.

如果我做一个VM"预热"并在计时之前运行几百次,我仍然会得到大约2000-4000 ns(800-1000以下).(如上所述,我听到其他人报告<100 ns ..并且比频繁呼叫时加起来高10到20倍.)

这是正常速度吗?什么可能导致我的本机代码被调用这么慢?

更新:

JNIEXPORT jint JNICALL Java_com_snap2d_gl_RenderControl_correctGammaNative
  (JNIEnv *env, jobject obj, jint pixel) {
    return X2D_correctGamma(pixel, 1.0f);
}
Run Code Online (Sandbox Code Playgroud)

其中X2D_correctGamma(int,float)是一种校正像素伽玛值的方法(自发布以来我实现了本机代码).

Java基准测试:

    for(int i = 0; i < 100; i++) {
        long t1 = System.nanoTime();
        correctGammaNative(0xFFF);
        long t2 = System.nanoTime();
        System.out.println(t2 - t1);
    }
Run Code Online (Sandbox Code Playgroud)

这是"热身"代码.初次调用后,大多数printlns读取800-1000ns.

不幸的是,我可能不得不废弃它,因为它应该用于渲染,并且每秒调用数千次将帧速率降低到1 FPS.

系统信息:

行为类似:JDK1.6.0_32(64位),JDK1.7.0_04(64位)和JRE1.7.0_10(32位)

Windows 7 64位

16GB RAM

i7-3770四核CPU @ 3.4-3.9ghz

GNU GCC MinGW编译器(32位和64位)

Ste*_*n C 7

这是正常速度吗?

不.如果你真的在每个JNI电话上获得50,000-80,000 ns,那就会发生一些奇怪的事情.

什么可能导致我的本机代码被调用这么慢?

不知道.它几乎可以是任何东西.但是如果你向我们展示了本机代码和Java代码,我们就可以更好地解释了.

我的钱将在这不是JNI呼叫的问题.相反,我希望它是您进行基准测试的方式的人工制品.您可以做很多事情(或者不做)会导致Java基准测试产生虚假结果.我们需要查看您的基准测试代码.


好的,您的更新表明您之前报告的时间(50,000-80,000或2000-4000)不正确或不相关.鉴于以下情况,800-1000ns的计时听起来似乎是合理的.

我认为你的基准测试有三个缺陷.

  • 您正在尝试测量几纳秒的时间间隔.但是你的测量没有考虑的是呼叫System.nanoTime()花费了大量时间.您需要做的是测量在每对呼叫之间进行几次或几百次JNI呼叫所需的时间System.nanoTime(),然后计算并打印平均值.

  • 您的代码不会将执行JNI调用所花费的时间与执行调用主体所花费的时间分开.(或者它可能......并且你没有向我们展示那些代码.)我怀疑伽马校正将比JNI呼叫开销花费更长的时间.

  • 你的热身不足.令人怀疑的是,你运行代码已经足够长时间以便JIT编译了.此外,你的基准代码仅限于单个方法调用的事实意味着即使JIT编译器运行了,你也可能会' d从不调用该方法的JIT编译版本.将基准代码放入方法并重复调用该方法.